forked from OpenWF/SpaceNinjaServer
Compare commits
2 Commits
main
...
fish-abbre
| Author | SHA1 | Date | |
|---|---|---|---|
| 9a76fb7e95 | |||
| 39c1a79d89 |
@ -3,6 +3,3 @@
|
|||||||
Dockerfile*
|
Dockerfile*
|
||||||
.*
|
.*
|
||||||
docker-data/
|
docker-data/
|
||||||
node_modules/
|
|
||||||
static/data/
|
|
||||||
logs/
|
|
||||||
|
|||||||
38
.eslintrc
38
.eslintrc
@ -1,48 +1,36 @@
|
|||||||
{
|
{
|
||||||
"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/consistent-type-imports": "error",
|
"@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": "error",
|
"@typescript-eslint/no-unsafe-call": "warn",
|
||||||
"@typescript-eslint/no-unsafe-assignment": "error",
|
"@typescript-eslint/no-unsafe-assignment": "warn",
|
||||||
"@typescript-eslint/no-explicit-any": "off",
|
"@typescript-eslint/no-explicit-any": "warn",
|
||||||
"no-loss-of-precision": "error",
|
"no-loss-of-precision": "warn",
|
||||||
"@typescript-eslint/no-unnecessary-condition": "error",
|
"@typescript-eslint/no-unnecessary-condition": "warn",
|
||||||
"@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",
|
||||||
"@typescript-eslint/require-await": "error",
|
"require-await": "off",
|
||||||
"import/no-named-as-default-member": "off",
|
"@typescript-eslint/require-await": "error"
|
||||||
"import/no-cycle": "warn",
|
|
||||||
"@typescript-eslint/no-deprecated": "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
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
7
.github/workflows/build.yml
vendored
7
.github/workflows/build.yml
vendored
@ -1,7 +1,6 @@
|
|||||||
name: Build
|
name: Build
|
||||||
on:
|
on:
|
||||||
push:
|
push: {}
|
||||||
branches: ["main"]
|
|
||||||
pull_request: {}
|
pull_request: {}
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
@ -11,10 +10,8 @@ jobs:
|
|||||||
uses: actions/checkout@v4.1.2
|
uses: actions/checkout@v4.1.2
|
||||||
- name: Setup Node.js environment
|
- name: Setup Node.js environment
|
||||||
uses: actions/setup-node@v4.0.2
|
uses: actions/setup-node@v4.0.2
|
||||||
with:
|
|
||||||
node-version: ">=20.18.1"
|
|
||||||
- run: npm ci
|
- run: npm ci
|
||||||
- run: cp config-vanilla.json config.json
|
- run: cp config.json.example 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
|
||||||
|
|||||||
25
.github/workflows/docker.yml
vendored
25
.github/workflows/docker.yml
vendored
@ -4,9 +4,9 @@ on:
|
|||||||
branches:
|
branches:
|
||||||
- main
|
- main
|
||||||
jobs:
|
jobs:
|
||||||
docker-amd64:
|
docker:
|
||||||
if: github.repository == 'OpenWF/SpaceNinjaServer'
|
if: github.repository == 'OpenWF/SpaceNinjaServer'
|
||||||
runs-on: amd64
|
runs-on: ubuntu-latest
|
||||||
steps:
|
steps:
|
||||||
- name: Set up Docker buildx
|
- name: Set up Docker buildx
|
||||||
uses: docker/setup-buildx-action@v3
|
uses: docker/setup-buildx-action@v3
|
||||||
@ -18,27 +18,8 @@ jobs:
|
|||||||
- name: Build and push
|
- name: Build and push
|
||||||
uses: docker/build-push-action@v6
|
uses: docker/build-push-action@v6
|
||||||
with:
|
with:
|
||||||
platforms: linux/amd64
|
platforms: linux/amd64,linux/arm64
|
||||||
push: true
|
push: true
|
||||||
tags: |
|
tags: |
|
||||||
openwf/spaceninjaserver:latest
|
openwf/spaceninjaserver:latest
|
||||||
openwf/spaceninjaserver:${{ github.sha }}
|
openwf/spaceninjaserver:${{ github.sha }}
|
||||||
docker-arm64:
|
|
||||||
if: github.repository == 'OpenWF/SpaceNinjaServer'
|
|
||||||
runs-on: arm64
|
|
||||||
steps:
|
|
||||||
- name: Set up Docker buildx
|
|
||||||
uses: docker/setup-buildx-action@v3
|
|
||||||
- name: Log in to container registry
|
|
||||||
uses: docker/login-action@v3
|
|
||||||
with:
|
|
||||||
username: openwf
|
|
||||||
password: ${{ secrets.DOCKERHUB_TOKEN }}
|
|
||||||
- name: Build and push
|
|
||||||
uses: docker/build-push-action@v6
|
|
||||||
with:
|
|
||||||
platforms: linux/arm64
|
|
||||||
push: true
|
|
||||||
tags: |
|
|
||||||
openwf/spaceninjaserver:latest-arm64
|
|
||||||
openwf/spaceninjaserver:${{ github.sha }}-arm64
|
|
||||||
|
|||||||
@ -2,4 +2,3 @@ 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,7 +8,8 @@
|
|||||||
"type": "node",
|
"type": "node",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"name": "Debug and Watch",
|
"name": "Debug and Watch",
|
||||||
"args": ["${workspaceFolder}/scripts/dev.js"],
|
"runtimeArgs": ["-r", "tsconfig-paths/register", "-r", "ts-node/register", "--watch-path", "src"],
|
||||||
|
"args": ["${workspaceFolder}/src/index.ts"],
|
||||||
"console": "integratedTerminal"
|
"console": "integratedTerminal"
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
|
|||||||
3
.vscode/settings.json
vendored
3
.vscode/settings.json
vendored
@ -1,3 +0,0 @@
|
|||||||
{
|
|
||||||
"typescript.preferences.preferTypeOnlyAutoImports": true
|
|
||||||
}
|
|
||||||
@ -1,19 +0,0 @@
|
|||||||
## In General
|
|
||||||
|
|
||||||
### Prerequisites
|
|
||||||
|
|
||||||
Use `npm i` or `npm ci` to install all dependencies, including dev dependencies.
|
|
||||||
|
|
||||||
## Development Process
|
|
||||||
|
|
||||||
Auto reloading is supported for server and WebUI development. Simply use `npm run dev` or `npm run dev:bun` to start the server and edit away.
|
|
||||||
|
|
||||||
### Testing
|
|
||||||
|
|
||||||
Before submitting a PR:
|
|
||||||
- Use `npm run verify` to verify that the code is type-safe.
|
|
||||||
- Use `npm run fix` to fix formatting issues as well as be informed of any unfixable issues. Avoid introducing new warnings.
|
|
||||||
|
|
||||||
## WebUI Specific
|
|
||||||
|
|
||||||
The translation system is designed around additions being made to `static/webui/translations/en.js`. They are copied over for translation via `npm run update-translations`. DO NOT provide translations generated by AI or other automated tools.
|
|
||||||
25
Dockerfile
25
Dockerfile
@ -1,11 +1,26 @@
|
|||||||
FROM node:24-alpine3.21
|
FROM node:18-alpine3.19
|
||||||
|
|
||||||
RUN apk add --no-cache bash jq
|
ENV APP_MONGODB_URL=mongodb://mongodb:27017/openWF
|
||||||
|
ENV APP_MY_ADDRESS=localhost
|
||||||
|
ENV APP_HTTP_PORT=80
|
||||||
|
ENV APP_HTTPS_PORT=443
|
||||||
|
ENV APP_AUTO_CREATE_ACCOUNT=true
|
||||||
|
ENV APP_SKIP_STORY_MODE_CHOICE=true
|
||||||
|
ENV APP_SKIP_TUTORIAL=true
|
||||||
|
ENV APP_SKIP_ALL_DIALOGUE=true
|
||||||
|
ENV APP_UNLOCK_ALL_SCANS=true
|
||||||
|
ENV APP_UNLOCK_ALL_MISSIONS=true
|
||||||
|
ENV APP_INFINITE_RESOURCES=true
|
||||||
|
ENV APP_UNLOCK_ALL_SHIP_FEATURES=true
|
||||||
|
ENV APP_UNLOCK_ALL_SHIP_DECORATIONS=true
|
||||||
|
ENV APP_UNLOCK_ALL_FLAVOUR_ITEMS=true
|
||||||
|
ENV APP_UNLOCK_ALL_SKINS=true
|
||||||
|
ENV APP_UNIVERSAL_POLARITY_EVERYWHERE=true
|
||||||
|
ENV APP_SPOOF_MASTERY_RANK=-1
|
||||||
|
|
||||||
|
RUN apk add --no-cache bash sed wget jq
|
||||||
|
|
||||||
COPY . /app
|
COPY . /app
|
||||||
WORKDIR /app
|
WORKDIR /app
|
||||||
|
|
||||||
RUN npm i --omit=dev --omit=optional
|
|
||||||
RUN date '+%d %B %Y' > BUILD_DATE
|
|
||||||
|
|
||||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||||
|
|||||||
30
README.md
30
README.md
@ -6,34 +6,12 @@ More information for the moment here: [https://discord.gg/PNNZ3asUuY](https://di
|
|||||||
|
|
||||||
This project is in active development at <https://onlyg.it/OpenWF/SpaceNinjaServer>.
|
This project is in active development at <https://onlyg.it/OpenWF/SpaceNinjaServer>.
|
||||||
|
|
||||||
To get an idea of what functionality you can expect to be missing [have a look through the issues](https://onlyg.it/OpenWF/SpaceNinjaServer/issues). However, many things have been implemented and *should* work as expected. Please open an issue for anything where that's not the case and/or the server is reporting errors.
|
To get an idea of what functionality you can expect to be missing [have a look through the issues](https://onlyg.it/OpenWF/SpaceNinjaServer/issues?q=&type=all&state=open&labels=-4%2C-10&milestone=0&assignee=0&poster=). However, many things have been implemented and *should* work as expected. Please open an issue for anything where that's not the case and/or the server is reporting errors.
|
||||||
|
|
||||||
## config.json
|
## config.json
|
||||||
|
|
||||||
SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config-vanilla.json](config-vanilla.json), which has most cheats disabled.
|
SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [config.json.example](config.json.example), which has most cheats disabled.
|
||||||
|
|
||||||
- `skipTutorial` affects only newly created accounts, so you may wish to change it before logging in for the first time.
|
|
||||||
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
|
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
|
||||||
- `ircAddress`, `hubAddress`, and `nrsAddress` are not present by default but can be provided if these secondary servers are on a different machine.
|
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
|
||||||
- `worldState.eidolonOverride` can be set to `day` or `night` to lock the time to day/fass and night/vome on Plains of Eidolon/Cambion Drift.
|
- `worldState.lockTime` will lock the time provided in worldState if nonzero, e.g. `1743202800` for night in POE.
|
||||||
- `worldState.vallisOverride` can be set to `warm` or `cold` to lock the temperature on Orb Vallis.
|
|
||||||
- `worldState.duviriOverride` can be set to `joy`, `anger`, `envy`, `sorrow`, or `fear` to lock the Duviri spiral.
|
|
||||||
- `worldState.nightwaveOverride` will lock the nightwave season, assuming the client is new enough for it. Valid values:
|
|
||||||
- `RadioLegionIntermission13Syndicate` for Nora's Mix Vol. 9
|
|
||||||
- `RadioLegionIntermission12Syndicate` for Nora's Mix Vol. 8
|
|
||||||
- `RadioLegionIntermission11Syndicate` for Nora's Mix Vol. 7
|
|
||||||
- `RadioLegionIntermission10Syndicate` for Nora's Mix Vol. 6
|
|
||||||
- `RadioLegionIntermission9Syndicate` for Nora's Mix Vol. 5
|
|
||||||
- `RadioLegionIntermission8Syndicate` for Nora's Mix Vol. 4
|
|
||||||
- `RadioLegionIntermission7Syndicate` for Nora's Mix Vol. 3
|
|
||||||
- `RadioLegionIntermission6Syndicate` for Nora's Mix Vol. 2
|
|
||||||
- `RadioLegionIntermission5Syndicate` for Nora's Mix Vol. 1
|
|
||||||
- `RadioLegionIntermission4Syndicate` for Nora's Choice
|
|
||||||
- `RadioLegionIntermission3Syndicate` for Intermission III
|
|
||||||
- `RadioLegion3Syndicate` for Glassmaker
|
|
||||||
- `RadioLegionIntermission2Syndicate` for Intermission II
|
|
||||||
- `RadioLegion2Syndicate` for The Emissary
|
|
||||||
- `RadioLegionIntermissionSyndicate` for Intermission I
|
|
||||||
- `RadioLegionSyndicate` for The Wolf of Saturn Six
|
|
||||||
- `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`.
|
|
||||||
|
|||||||
@ -1,33 +1,26 @@
|
|||||||
@echo off
|
@echo off
|
||||||
|
|
||||||
echo Updating SpaceNinjaServer...
|
echo Updating SpaceNinjaServer...
|
||||||
|
git config remote.origin.url https://openwf.io/SpaceNinjaServer.git
|
||||||
git fetch --prune
|
git fetch --prune
|
||||||
if %errorlevel% == 0 (
|
git stash
|
||||||
git stash
|
git reset --hard origin/main
|
||||||
git checkout -f origin/main
|
|
||||||
|
|
||||||
if exist static\data\0\ (
|
if exist static\data\0\ (
|
||||||
echo Updating stripped assets...
|
echo Updating stripped assets...
|
||||||
cd static\data\0\
|
cd static\data\0\
|
||||||
git pull
|
git pull
|
||||||
cd ..\..\..\
|
cd ..\..\..\
|
||||||
)
|
|
||||||
|
|
||||||
echo Updating dependencies...
|
|
||||||
node scripts/raw-precheck.js > NUL
|
|
||||||
if %errorlevel% == 0 (
|
|
||||||
call npm i --omit=dev --omit=optional
|
|
||||||
call npm run raw
|
|
||||||
) else (
|
|
||||||
call npm i --omit=dev
|
|
||||||
call npm run build
|
|
||||||
if %errorlevel% == 0 (
|
|
||||||
call npm run start
|
|
||||||
)
|
|
||||||
)
|
|
||||||
echo SpaceNinjaServer seems to have crashed.
|
|
||||||
)
|
)
|
||||||
|
|
||||||
|
echo Updating dependencies...
|
||||||
|
call npm i --omit=dev
|
||||||
|
|
||||||
|
call npm run build
|
||||||
|
if %errorlevel% == 0 (
|
||||||
|
call npm run start
|
||||||
|
echo SpaceNinjaServer seems to have crashed.
|
||||||
|
)
|
||||||
:a
|
:a
|
||||||
pause > nul
|
pause > nul
|
||||||
goto a
|
goto a
|
||||||
|
|||||||
@ -1,29 +0,0 @@
|
|||||||
#!/bin/bash
|
|
||||||
|
|
||||||
echo "Updating SpaceNinjaServer..."
|
|
||||||
git fetch --prune
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
git stash
|
|
||||||
git checkout -f origin/main
|
|
||||||
|
|
||||||
if [ -d "static/data/0/" ]; then
|
|
||||||
echo "Updating stripped assets..."
|
|
||||||
cd static/data/0/
|
|
||||||
git pull
|
|
||||||
cd ../../../
|
|
||||||
fi
|
|
||||||
|
|
||||||
echo "Updating dependencies..."
|
|
||||||
node scripts/raw-precheck.js > /dev/null
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
npm i --omit=dev --omit=optional
|
|
||||||
npm run raw
|
|
||||||
else
|
|
||||||
npm i --omit=dev
|
|
||||||
npm run build
|
|
||||||
if [ $? -eq 0 ]; then
|
|
||||||
npm run start
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
echo "SpaceNinjaServer seems to have crashed."
|
|
||||||
fi
|
|
||||||
@ -1,67 +0,0 @@
|
|||||||
{
|
|
||||||
"mongodbUrl": "mongodb://127.0.0.1:27017/openWF",
|
|
||||||
"logger": {
|
|
||||||
"files": true,
|
|
||||||
"level": "trace"
|
|
||||||
},
|
|
||||||
"myAddress": "localhost",
|
|
||||||
"bindAddress": "0.0.0.0",
|
|
||||||
"httpPort": 80,
|
|
||||||
"httpsPort": 443,
|
|
||||||
"administratorNames": [],
|
|
||||||
"autoCreateAccount": true,
|
|
||||||
"skipTutorial": false,
|
|
||||||
"unlockAllSkins": false,
|
|
||||||
"fullyStockedVendors": false,
|
|
||||||
"skipClanKeyCrafting": false,
|
|
||||||
"spoofMasteryRank": -1,
|
|
||||||
"relicRewardItemCountMultiplier": 1,
|
|
||||||
"nightwaveStandingMultiplier": 1,
|
|
||||||
"unfaithfulBugFixes": {
|
|
||||||
"ignore1999LastRegionPlayed": false,
|
|
||||||
"fixXtraCheeseTimer": false,
|
|
||||||
"useAnniversaryTagForOldGoals": true
|
|
||||||
},
|
|
||||||
"worldState": {
|
|
||||||
"creditBoost": false,
|
|
||||||
"affinityBoost": false,
|
|
||||||
"resourceBoost": false,
|
|
||||||
"tennoLiveRelay": false,
|
|
||||||
"baroTennoConRelay": false,
|
|
||||||
"baroAlwaysAvailable": false,
|
|
||||||
"baroFullyStocked": false,
|
|
||||||
"varziaFullyStocked": false,
|
|
||||||
"wolfHunt": false,
|
|
||||||
"orphixVenom": false,
|
|
||||||
"longShadow": false,
|
|
||||||
"hallowedFlame": false,
|
|
||||||
"anniversary": null,
|
|
||||||
"hallowedNightmares": false,
|
|
||||||
"hallowedNightmaresRewardsOverride": 0,
|
|
||||||
"proxyRebellion": false,
|
|
||||||
"proxyRebellionRewardsOverride": 0,
|
|
||||||
"galleonOfGhouls": 0,
|
|
||||||
"ghoulEmergenceOverride": null,
|
|
||||||
"plagueStarOverride": null,
|
|
||||||
"starDaysOverride": null,
|
|
||||||
"dogDaysOverride": null,
|
|
||||||
"dogDaysRewardsOverride": null,
|
|
||||||
"bellyOfTheBeast": false,
|
|
||||||
"bellyOfTheBeastProgressOverride": 0,
|
|
||||||
"eightClaw": false,
|
|
||||||
"eightClawProgressOverride": 0,
|
|
||||||
"thermiaFracturesOverride": null,
|
|
||||||
"thermiaFracturesProgressOverride": 0,
|
|
||||||
"eidolonOverride": "",
|
|
||||||
"vallisOverride": "",
|
|
||||||
"duviriOverride": "",
|
|
||||||
"nightwaveOverride": "",
|
|
||||||
"allTheFissures": "",
|
|
||||||
"varziaOverride": "",
|
|
||||||
"circuitGameModes": null,
|
|
||||||
"darvoStockMultiplier": 1
|
|
||||||
},
|
|
||||||
"dev": {
|
|
||||||
"keepVendorsExpired": false
|
|
||||||
}
|
|
||||||
}
|
|
||||||
54
config.json.example
Normal file
54
config.json.example
Normal file
@ -0,0 +1,54 @@
|
|||||||
|
{
|
||||||
|
"mongodbUrl": "mongodb://127.0.0.1:27017/openWF",
|
||||||
|
"logger": {
|
||||||
|
"files": true,
|
||||||
|
"level": "trace"
|
||||||
|
},
|
||||||
|
"myAddress": "localhost",
|
||||||
|
"httpPort": 80,
|
||||||
|
"httpsPort": 443,
|
||||||
|
"NRS": ["localhost"],
|
||||||
|
"administratorNames": [],
|
||||||
|
"autoCreateAccount": true,
|
||||||
|
"skipTutorial": false,
|
||||||
|
"skipAllDialogue": false,
|
||||||
|
"unlockAllScans": false,
|
||||||
|
"unlockAllMissions": false,
|
||||||
|
"infiniteCredits": false,
|
||||||
|
"infinitePlatinum": false,
|
||||||
|
"infiniteEndo": false,
|
||||||
|
"infiniteRegalAya": false,
|
||||||
|
"infiniteHelminthMaterials": false,
|
||||||
|
"unlockAllShipFeatures": false,
|
||||||
|
"unlockAllShipDecorations": false,
|
||||||
|
"unlockAllFlavourItems": false,
|
||||||
|
"unlockAllSkins": false,
|
||||||
|
"unlockAllCapturaScenes": false,
|
||||||
|
"universalPolarityEverywhere": false,
|
||||||
|
"unlockDoubleCapacityPotatoesEverywhere": false,
|
||||||
|
"unlockExilusEverywhere": false,
|
||||||
|
"unlockArcanesEverywhere": false,
|
||||||
|
"noDailyStandingLimits": false,
|
||||||
|
"noDailyFocusLimit": false,
|
||||||
|
"noArgonCrystalDecay": false,
|
||||||
|
"noMasteryRankUpCooldown": false,
|
||||||
|
"noVendorPurchaseLimits": true,
|
||||||
|
"noDeathMarks": false,
|
||||||
|
"noKimCooldowns": false,
|
||||||
|
"instantResourceExtractorDrones": false,
|
||||||
|
"noResourceExtractorDronesDamage": false,
|
||||||
|
"noDojoRoomBuildStage": false,
|
||||||
|
"noDecoBuildStage": false,
|
||||||
|
"fastDojoRoomDestruction": false,
|
||||||
|
"noDojoResearchCosts": false,
|
||||||
|
"noDojoResearchTime": false,
|
||||||
|
"fastClanAscension": false,
|
||||||
|
"spoofMasteryRank": -1,
|
||||||
|
"worldState": {
|
||||||
|
"creditBoost": false,
|
||||||
|
"affinityBoost": false,
|
||||||
|
"resourceBoost": false,
|
||||||
|
"starDays": true,
|
||||||
|
"lockTime": 0
|
||||||
|
}
|
||||||
|
}
|
||||||
@ -1,20 +1,37 @@
|
|||||||
services:
|
services:
|
||||||
spaceninjaserver:
|
spaceninjaserver:
|
||||||
# The image to use. If you have an ARM CPU, replace 'latest' with 'latest-arm64'.
|
# build: .
|
||||||
image: openwf/spaceninjaserver:latest
|
image: openwf/spaceninjaserver:latest
|
||||||
|
environment:
|
||||||
|
APP_MONGODB_URL: mongodb://openwfagent:spaceninjaserver@mongodb:27017/
|
||||||
|
|
||||||
|
# Following environment variables are set to default image values.
|
||||||
|
# Uncomment to edit.
|
||||||
|
|
||||||
|
# APP_MY_ADDRESS: localhost
|
||||||
|
# APP_HTTP_PORT: 80
|
||||||
|
# APP_HTTPS_PORT: 443
|
||||||
|
# APP_AUTO_CREATE_ACCOUNT: true
|
||||||
|
# APP_SKIP_STORY_MODE_CHOICE: true
|
||||||
|
# APP_SKIP_TUTORIAL: true
|
||||||
|
# APP_SKIP_ALL_DIALOGUE: true
|
||||||
|
# APP_UNLOCK_ALL_SCANS: true
|
||||||
|
# APP_UNLOCK_ALL_MISSIONS: true
|
||||||
|
# APP_UNLOCK_ALL_QUESTS: true
|
||||||
|
# APP_COMPLETE_ALL_QUESTS: true
|
||||||
|
# APP_INFINITE_RESOURCES: true
|
||||||
|
# APP_UNLOCK_ALL_SHIP_FEATURES: true
|
||||||
|
# APP_UNLOCK_ALL_SHIP_DECORATIONS: true
|
||||||
|
# APP_UNLOCK_ALL_FLAVOUR_ITEMS: true
|
||||||
|
# APP_UNLOCK_ALL_SKINS: true
|
||||||
|
# APP_UNIVERSAL_POLARITY_EVERYWHERE: true
|
||||||
|
# APP_SPOOF_MASTERY_RANK: -1
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker-data/conf:/app/conf
|
- ./docker-data/static:/app/static/data
|
||||||
- ./docker-data/static-data:/app/static/data
|
|
||||||
- ./docker-data/logs:/app/logs
|
- ./docker-data/logs:/app/logs
|
||||||
ports:
|
ports:
|
||||||
- 80:80
|
- 80:80
|
||||||
- 443:443
|
- 443:443
|
||||||
|
|
||||||
# Normally, the image is fetched from Docker Hub, but you can use the local Dockerfile by removing "image" above and adding this:
|
|
||||||
#build: .
|
|
||||||
# Works best when using `docker-compose up --force-recreate --build`.
|
|
||||||
|
|
||||||
depends_on:
|
depends_on:
|
||||||
- mongodb
|
- mongodb
|
||||||
mongodb:
|
mongodb:
|
||||||
@ -24,4 +41,3 @@ services:
|
|||||||
MONGO_INITDB_ROOT_PASSWORD: spaceninjaserver
|
MONGO_INITDB_ROOT_PASSWORD: spaceninjaserver
|
||||||
volumes:
|
volumes:
|
||||||
- ./docker-data/database:/data/db
|
- ./docker-data/database:/data/db
|
||||||
command: mongod --quiet --logpath /dev/null
|
|
||||||
|
|||||||
@ -1,8 +1,23 @@
|
|||||||
#!/bin/bash
|
#!/bin/bash
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
if [ ! -f conf/config.json ]; then
|
# Set up the configuration file using environment variables.
|
||||||
jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config-vanilla.json > /app/conf/config.json
|
echo '{
|
||||||
fi
|
"logger": {
|
||||||
|
"files": true,
|
||||||
|
"level": "trace",
|
||||||
|
"__valid_levels": "fatal, error, warn, info, http, debug, trace"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
' > config.json
|
||||||
|
|
||||||
exec npm run raw -- --configPath conf/config.json
|
for config in $(env | grep "APP_")
|
||||||
|
do
|
||||||
|
var=$(echo "${config}" | tr '[:upper:]' '[:lower:]' | sed 's/app_//g' | sed -E 's/_([a-z])/\U\1/g' | sed 's/=.*//g')
|
||||||
|
val=$(echo "${config}" | sed 's/.*=//g')
|
||||||
|
jq --arg variable "$var" --arg value "$val" '.[$variable] += try [$value|fromjson][] catch $value' config.json > config.tmp
|
||||||
|
mv config.tmp config.json
|
||||||
|
done
|
||||||
|
|
||||||
|
npm install
|
||||||
|
exec npm run dev
|
||||||
|
|||||||
3487
package-lock.json
generated
3487
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
48
package.json
48
package.json
@ -4,62 +4,44 @@
|
|||||||
"description": "WF Emulator",
|
"description": "WF Emulator",
|
||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --enable-source-maps build/src/index.js",
|
"start": "node --enable-source-maps --import ./build/src/pathman.js build/src/index.js",
|
||||||
"build": "tsgo --inlineSourceMap && ncp static/webui build/static/webui",
|
"dev": "ts-node-dev --openssl-legacy-provider -r tsconfig-paths/register src/index.ts ",
|
||||||
"build:tsc": "tsc --incremental --inlineSourceMap && ncp static/webui build/static/webui",
|
"build": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
|
||||||
"build:dev": "tsgo --inlineSourceMap",
|
|
||||||
"build:dev:tsc": "tsc --incremental --inlineSourceMap",
|
|
||||||
"build-and-start": "npm run build && npm run start",
|
|
||||||
"build-and-start:bun": "npm run verify && npm run bun-run",
|
|
||||||
"dev": "node scripts/dev.cjs",
|
|
||||||
"dev:bun": "bun scripts/dev.cjs",
|
|
||||||
"verify": "tsgo --noEmit",
|
"verify": "tsgo --noEmit",
|
||||||
"verify:tsc": "tsc --noEmit",
|
|
||||||
"raw": "node scripts/raw-precheck.js && node --experimental-transform-types src/index.ts",
|
|
||||||
"raw:bun": "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.cjs",
|
"update-translations": "cd scripts && node update-translations.js"
|
||||||
"fix": "npm run update-translations && npm run lint:fix"
|
|
||||||
},
|
},
|
||||||
"license": "GNU",
|
"license": "GNU",
|
||||||
"type": "module",
|
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"chokidar": "^4.0.3",
|
"@types/express": "^5",
|
||||||
|
"@types/morgan": "^1.9.9",
|
||||||
"crc-32": "^1.2.2",
|
"crc-32": "^1.2.2",
|
||||||
"express": "^5",
|
"express": "^5",
|
||||||
"json-with-bigint": "^3.4.4",
|
"json-with-bigint": "^3.2.2",
|
||||||
"mongoose": "^8.11.0",
|
"mongoose": "^8.11.0",
|
||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"undici": "^7.10.0",
|
"typescript": "^5.5",
|
||||||
"warframe-public-export-plus": "^0.5.89",
|
"warframe-public-export-plus": "^0.5.57",
|
||||||
"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"
|
||||||
"ws": "^8.18.2"
|
|
||||||
},
|
|
||||||
"optionalDependencies": {
|
|
||||||
"@types/express": "^5",
|
|
||||||
"@types/morgan": "^1.9.9",
|
|
||||||
"@types/websocket": "^1.0.10",
|
|
||||||
"@types/ws": "^8.18.1",
|
|
||||||
"@typescript/native-preview": "^7.0.0-dev.20250625.1",
|
|
||||||
"typescript": "^5.7"
|
|
||||||
},
|
},
|
||||||
"devDependencies": {
|
"devDependencies": {
|
||||||
|
"@rxliuli/tsgo": "^2025.3.31",
|
||||||
"@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",
|
||||||
"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"
|
"ts-node-dev": "^2.0.0",
|
||||||
|
"tsconfig-paths": "^4.2.0"
|
||||||
},
|
},
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": ">=20.18.1"
|
"node": ">=18.15.0",
|
||||||
|
"npm": ">=9.5.0"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,73 +0,0 @@
|
|||||||
/* eslint-disable */
|
|
||||||
const { spawn } = require("child_process");
|
|
||||||
const chokidar = require("chokidar");
|
|
||||||
const kill = require("tree-kill");
|
|
||||||
|
|
||||||
let secret = "";
|
|
||||||
for (let i = 0; i != 10; ++i) {
|
|
||||||
secret += String.fromCharCode(Math.floor(Math.random() * 26) + 0x41);
|
|
||||||
}
|
|
||||||
|
|
||||||
const args = [...process.argv].splice(2);
|
|
||||||
args.push("--dev");
|
|
||||||
args.push("--secret");
|
|
||||||
args.push(secret);
|
|
||||||
|
|
||||||
const cangoraw = (() => {
|
|
||||||
if (process.versions.bun) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
const [major, minor] = process.versions.node.split(".").map(x => parseInt(x));
|
|
||||||
if (major > 22 || (major == 22 && minor >= 7)) {
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
return false;
|
|
||||||
})();
|
|
||||||
|
|
||||||
let buildproc, runproc;
|
|
||||||
const spawnopts = { stdio: "inherit", shell: true };
|
|
||||||
function run(changedFile) {
|
|
||||||
if (changedFile) {
|
|
||||||
console.log(`Change to ${changedFile} detected`);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (buildproc) {
|
|
||||||
kill(buildproc.pid);
|
|
||||||
buildproc = undefined;
|
|
||||||
}
|
|
||||||
if (runproc) {
|
|
||||||
kill(runproc.pid);
|
|
||||||
runproc = undefined;
|
|
||||||
}
|
|
||||||
|
|
||||||
const thisbuildproc = spawn("npm", ["run", cangoraw ? "verify" : "build:dev"], spawnopts);
|
|
||||||
const thisbuildstart = Date.now();
|
|
||||||
buildproc = thisbuildproc;
|
|
||||||
buildproc.on("exit", code => {
|
|
||||||
if (buildproc !== thisbuildproc) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
buildproc = undefined;
|
|
||||||
if (code === 0) {
|
|
||||||
console.log(`${cangoraw ? "Verified" : "Built"} in ${Date.now() - thisbuildstart} ms`);
|
|
||||||
runproc = spawn(
|
|
||||||
"npm",
|
|
||||||
["run", cangoraw ? (process.versions.bun ? "raw:bun" : "raw") : "start", "--", ...args],
|
|
||||||
spawnopts
|
|
||||||
);
|
|
||||||
runproc.on("exit", () => {
|
|
||||||
runproc = undefined;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
run();
|
|
||||||
chokidar.watch("src").on("change", run);
|
|
||||||
chokidar.watch("static/fixed_responses").on("change", run);
|
|
||||||
|
|
||||||
chokidar.watch("static/webui").on("change", async () => {
|
|
||||||
try {
|
|
||||||
await fetch("http://localhost/custom/webuiFileChangeDetected?secret=" + secret);
|
|
||||||
} catch (e) {}
|
|
||||||
});
|
|
||||||
@ -1,9 +0,0 @@
|
|||||||
const [major, minor] = process.versions.node.split(".").map(x => parseInt(x));
|
|
||||||
if (major > 22 || (major == 22 && minor >= 7)) {
|
|
||||||
// ok
|
|
||||||
} else {
|
|
||||||
console.log("Sorry, your Node version is a bit too old for this. You have 2 options:");
|
|
||||||
console.log("- Update Node.js.");
|
|
||||||
console.log("- Use 'npm run build && npm run start'. Optional libraries must be installed for this.");
|
|
||||||
process.exit(1);
|
|
||||||
}
|
|
||||||
@ -1,7 +1,6 @@
|
|||||||
// Based on https://onlyg.it/OpenWF/Translations/src/branch/main/update.php
|
// Based on https://onlyg.it/OpenWF/Translations/src/branch/main/update.php
|
||||||
// Converted via ChatGPT-4o
|
// Converted via ChatGPT-4o
|
||||||
|
|
||||||
/* eslint-disable */
|
|
||||||
const fs = require("fs");
|
const fs = require("fs");
|
||||||
|
|
||||||
function extractStrings(content) {
|
function extractStrings(content) {
|
||||||
@ -31,7 +30,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) && !targetStrings[key].startsWith("[UNTRANSLATED]")) {
|
if (targetStrings.hasOwnProperty(key)) {
|
||||||
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`);
|
||||||
27
src/app.ts
27
src/app.ts
@ -1,17 +1,17 @@
|
|||||||
import express from "express";
|
import express from "express";
|
||||||
|
|
||||||
import bodyParser from "body-parser";
|
import bodyParser from "body-parser";
|
||||||
import { unknownEndpointHandler } from "./middleware/middleware.ts";
|
import { unknownEndpointHandler } from "@/src/middleware/middleware";
|
||||||
import { requestLogger } from "./middleware/morgenMiddleware.ts";
|
import { requestLogger } from "@/src/middleware/morgenMiddleware";
|
||||||
import { errorHandler } from "./middleware/errorHandler.ts";
|
import { errorHandler } from "@/src/middleware/errorHandler";
|
||||||
|
|
||||||
import { apiRouter } from "./routes/api.ts";
|
import { apiRouter } from "@/src/routes/api";
|
||||||
import { cacheRouter } from "./routes/cache.ts";
|
import { cacheRouter } from "@/src/routes/cache";
|
||||||
import { customRouter } from "./routes/custom.ts";
|
import { customRouter } from "@/src/routes/custom";
|
||||||
import { dynamicController } from "./routes/dynamic.ts";
|
import { dynamicController } from "@/src/routes/dynamic";
|
||||||
import { payRouter } from "./routes/pay.ts";
|
import { payRouter } from "@/src/routes/pay";
|
||||||
import { statsRouter } from "./routes/stats.ts";
|
import { statsRouter } from "@/src/routes/stats";
|
||||||
import { webuiRouter } from "./routes/webui.ts";
|
import { webuiRouter } from "@/src/routes/webui";
|
||||||
|
|
||||||
const app = express();
|
const app = express();
|
||||||
|
|
||||||
@ -21,13 +21,6 @@ app.use((req, _res, next) => {
|
|||||||
if (req.headers["content-encoding"] == "ezip" || req.headers["content-encoding"] == "e") {
|
if (req.headers["content-encoding"] == "ezip" || req.headers["content-encoding"] == "e") {
|
||||||
req.headers["content-encoding"] = undefined;
|
req.headers["content-encoding"] = undefined;
|
||||||
}
|
}
|
||||||
|
|
||||||
// U18 uses application/x-www-form-urlencoded even tho the data is JSON which Express doesn't like.
|
|
||||||
// U17 sets no Content-Type at all, which Express also doesn't like.
|
|
||||||
if (!req.headers["content-type"] || req.headers["content-type"] == "application/x-www-form-urlencoded") {
|
|
||||||
req.headers["content-type"] = "application/octet-stream";
|
|
||||||
}
|
|
||||||
|
|
||||||
next();
|
next();
|
||||||
});
|
});
|
||||||
|
|
||||||
|
|||||||
@ -2,18 +2,15 @@ const millisecondsPerSecond = 1000;
|
|||||||
const secondsPerMinute = 60;
|
const secondsPerMinute = 60;
|
||||||
const minutesPerHour = 60;
|
const minutesPerHour = 60;
|
||||||
const hoursPerDay = 24;
|
const hoursPerDay = 24;
|
||||||
const daysPerWeek = 7;
|
|
||||||
|
|
||||||
const unixSecond = millisecondsPerSecond;
|
const unixSecond = millisecondsPerSecond;
|
||||||
const unixMinute = secondsPerMinute * millisecondsPerSecond;
|
const unixMinute = secondsPerMinute * millisecondsPerSecond;
|
||||||
const unixHour = unixMinute * minutesPerHour;
|
const unixHour = unixMinute * minutesPerHour;
|
||||||
const unixDay = hoursPerDay * unixHour;
|
const unixDay = hoursPerDay * unixHour;
|
||||||
const unixWeek = daysPerWeek * unixDay;
|
|
||||||
|
|
||||||
export const unixTimesInMs = {
|
export const unixTimesInMs = {
|
||||||
second: unixSecond,
|
second: unixSecond,
|
||||||
minute: unixMinute,
|
minute: unixMinute,
|
||||||
hour: unixHour,
|
hour: unixHour,
|
||||||
day: unixDay,
|
day: unixDay
|
||||||
week: unixWeek
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const abandonLibraryDailyTaskController: RequestHandler = async (req, res) => {
|
export const abandonLibraryDailyTaskController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -5,11 +5,11 @@ import {
|
|||||||
hasGuildPermission,
|
hasGuildPermission,
|
||||||
removeDojoDeco,
|
removeDojoDeco,
|
||||||
removeDojoRoom
|
removeDojoRoom
|
||||||
} from "../../services/guildService.ts";
|
} from "@/src/services/guildService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const abortDojoComponentController: RequestHandler = async (req, res) => {
|
export const abortDojoComponentController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,13 +1,8 @@
|
|||||||
import {
|
import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
|
||||||
getDojoClient,
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
getGuildForRequestEx,
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
hasAccessToDojo,
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
hasGuildPermission
|
import { RequestHandler } from "express";
|
||||||
} from "../../services/guildService.ts";
|
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const abortDojoComponentDestructionController: RequestHandler = async (req, res) => {
|
export const abortDojoComponentDestructionController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,19 +1,15 @@
|
|||||||
import { toOid } from "../../helpers/inventoryHelpers.ts";
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import {
|
import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper";
|
||||||
createVeiledRivenFingerprint,
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
createUnveiledRivenFingerprint,
|
import { addMods, getInventory } from "@/src/services/inventoryService";
|
||||||
rivenRawToRealWeighted
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
} from "../../helpers/rivenHelper.ts";
|
import { getRandomElement } from "@/src/services/rngService";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { RequestHandler } from "express";
|
||||||
import { addMods, getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import { getRandomElement } from "../../services/rngService.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
import { ExportUpgrades } from "warframe-public-export-plus";
|
import { ExportUpgrades } from "warframe-public-export-plus";
|
||||||
|
|
||||||
export const activateRandomModController: RequestHandler = async (req, res) => {
|
export const activateRandomModController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId, "RawUpgrades Upgrades instantFinishRivenChallenge");
|
const inventory = await getInventory(accountId);
|
||||||
const request = getJSONfromString<IActiveRandomModRequest>(String(req.body));
|
const request = getJSONfromString<IActiveRandomModRequest>(String(req.body));
|
||||||
addMods(inventory, [
|
addMods(inventory, [
|
||||||
{
|
{
|
||||||
@ -21,10 +17,8 @@ export const activateRandomModController: RequestHandler = async (req, res) => {
|
|||||||
ItemCount: -1
|
ItemCount: -1
|
||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType])!;
|
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType]);
|
||||||
const fingerprint = inventory.instantFinishRivenChallenge
|
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
||||||
? createUnveiledRivenFingerprint(ExportUpgrades[rivenType])
|
|
||||||
: createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
|
||||||
const upgradeIndex =
|
const upgradeIndex =
|
||||||
inventory.Upgrades.push({
|
inventory.Upgrades.push({
|
||||||
ItemType: rivenType,
|
ItemType: rivenType,
|
||||||
|
|||||||
@ -1,60 +0,0 @@
|
|||||||
import { toOid } from "../../helpers/inventoryHelpers.ts";
|
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
|
||||||
import { Friendship } from "../../models/friendModel.ts";
|
|
||||||
import { addAccountDataToFriendInfo, addInventoryDataToFriendInfo } from "../../services/friendService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import type { IFriendInfo } from "../../types/friendTypes.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const addFriendController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const payload = getJSONfromString<IAddFriendRequest>(String(req.body));
|
|
||||||
const promises: Promise<void>[] = [];
|
|
||||||
const newFriends: IFriendInfo[] = [];
|
|
||||||
if (payload.friend == "all") {
|
|
||||||
const [internalFriendships, externalFriendships] = await Promise.all([
|
|
||||||
Friendship.find({ owner: accountId }, "friend"),
|
|
||||||
Friendship.find({ friend: accountId }, "owner")
|
|
||||||
]);
|
|
||||||
for (const externalFriendship of externalFriendships) {
|
|
||||||
if (!internalFriendships.find(x => x.friend.equals(externalFriendship.owner))) {
|
|
||||||
promises.push(
|
|
||||||
Friendship.insertOne({
|
|
||||||
owner: accountId,
|
|
||||||
friend: externalFriendship.owner,
|
|
||||||
Note: externalFriendship.Note // TOVERIFY: Should the note be copied when accepting a friend request?
|
|
||||||
}) as unknown as Promise<void>
|
|
||||||
);
|
|
||||||
newFriends.push({
|
|
||||||
_id: toOid(externalFriendship.owner)
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const externalFriendship = await Friendship.findOne({ owner: payload.friend, friend: accountId }, "Note");
|
|
||||||
if (externalFriendship) {
|
|
||||||
promises.push(
|
|
||||||
Friendship.insertOne({
|
|
||||||
owner: accountId,
|
|
||||||
friend: payload.friend,
|
|
||||||
Note: externalFriendship.Note
|
|
||||||
}) as unknown as Promise<void>
|
|
||||||
);
|
|
||||||
newFriends.push({
|
|
||||||
_id: { $oid: payload.friend }
|
|
||||||
});
|
|
||||||
}
|
|
||||||
}
|
|
||||||
for (const newFriend of newFriends) {
|
|
||||||
promises.push(addAccountDataToFriendInfo(newFriend));
|
|
||||||
promises.push(addInventoryDataToFriendInfo(newFriend));
|
|
||||||
}
|
|
||||||
await Promise.all(promises);
|
|
||||||
res.json({
|
|
||||||
Friends: newFriends
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IAddFriendRequest {
|
|
||||||
friend: string; // oid or "all" in which case all=1 is also a query parameter
|
|
||||||
}
|
|
||||||
@ -1,7 +1,7 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { Inventory } from "../../models/inventoryModels/inventoryModel.ts";
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
|
|
||||||
export const addFriendImageController: RequestHandler = async (req, res) => {
|
export const addFriendImageController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { toOid } from "../../helpers/inventoryHelpers.ts";
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Account, Ignore } from "../../models/loginModel.ts";
|
import { Account, Ignore } from "@/src/models/loginModel";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { IFriendInfo } from "../../types/friendTypes.ts";
|
import { IFriendInfo } from "@/src/types/guildTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const addIgnoredUserController: RequestHandler = async (req, res) => {
|
export const addIgnoredUserController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,52 +0,0 @@
|
|||||||
import { toMongoDate, toOid } from "../../helpers/inventoryHelpers.ts";
|
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
|
||||||
import { Friendship } from "../../models/friendModel.ts";
|
|
||||||
import { Account } from "../../models/loginModel.ts";
|
|
||||||
import { addInventoryDataToFriendInfo, areFriendsOfFriends } from "../../services/friendService.ts";
|
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import type { IFriendInfo } from "../../types/friendTypes.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const addPendingFriendController: RequestHandler = async (req, res) => {
|
|
||||||
const payload = getJSONfromString<IAddPendingFriendRequest>(String(req.body));
|
|
||||||
|
|
||||||
const account = await Account.findOne({ DisplayName: payload.friend });
|
|
||||||
if (!account) {
|
|
||||||
res.status(400).end();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(account._id.toString(), "Settings");
|
|
||||||
if (
|
|
||||||
inventory.Settings?.FriendInvRestriction == "GIFT_MODE_NONE" ||
|
|
||||||
(inventory.Settings?.FriendInvRestriction == "GIFT_MODE_FRIENDS" &&
|
|
||||||
!(await areFriendsOfFriends(account._id, accountId)))
|
|
||||||
) {
|
|
||||||
res.status(400).send("Friend Invite Restriction");
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await Friendship.insertOne({
|
|
||||||
owner: accountId,
|
|
||||||
friend: account._id,
|
|
||||||
Note: payload.message
|
|
||||||
});
|
|
||||||
|
|
||||||
const friendInfo: IFriendInfo = {
|
|
||||||
_id: toOid(account._id),
|
|
||||||
DisplayName: account.DisplayName,
|
|
||||||
LastLogin: toMongoDate(account.LastLogin),
|
|
||||||
Note: payload.message
|
|
||||||
};
|
|
||||||
await addInventoryDataToFriendInfo(friendInfo);
|
|
||||||
res.json({
|
|
||||||
Friend: friendInfo
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IAddPendingFriendRequest {
|
|
||||||
friend: string;
|
|
||||||
message: string;
|
|
||||||
}
|
|
||||||
@ -1,11 +1,11 @@
|
|||||||
import { getJSONfromString, regexEscape } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString, regexEscape } from "@/src/helpers/stringHelpers";
|
||||||
import { Alliance, AllianceMember, Guild, GuildMember } from "../../models/guildModel.ts";
|
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { createMessage } from "../../services/inboxService.ts";
|
import { createMessage } from "@/src/services/inboxService";
|
||||||
import { getEffectiveAvatarImageType, getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountForRequest, getSuffixedName } from "../../services/loginService.ts";
|
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
import { logger } from "../../utils/logger.ts";
|
import { logger } from "@/src/utils/logger";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ExportFlavour } from "warframe-public-export-plus";
|
import { ExportFlavour } from "warframe-public-export-plus";
|
||||||
|
|
||||||
export const addToAllianceController: RequestHandler = async (req, res) => {
|
export const addToAllianceController: RequestHandler = async (req, res) => {
|
||||||
@ -75,7 +75,7 @@ export const addToAllianceController: RequestHandler = async (req, res) => {
|
|||||||
const invitedClanOwnerMember = (await GuildMember.findOne({ guildId: guilds[0]._id, rank: 0 }))!;
|
const invitedClanOwnerMember = (await GuildMember.findOne({ guildId: guilds[0]._id, rank: 0 }))!;
|
||||||
const senderInventory = await getInventory(account._id.toString(), "ActiveAvatarImageType");
|
const senderInventory = await getInventory(account._id.toString(), "ActiveAvatarImageType");
|
||||||
const senderGuild = (await Guild.findById(allianceMember.guildId, "Name"))!;
|
const senderGuild = (await Guild.findById(allianceMember.guildId, "Name"))!;
|
||||||
const alliance = (await Alliance.findById(req.query.allianceId as string, "Name"))!;
|
const alliance = (await Alliance.findById(req.query.allianceId, "Name"))!;
|
||||||
await createMessage(invitedClanOwnerMember.accountId, [
|
await createMessage(invitedClanOwnerMember.accountId, [
|
||||||
{
|
{
|
||||||
sndr: getSuffixedName(account),
|
sndr: getSuffixedName(account),
|
||||||
@ -95,7 +95,7 @@ export const addToAllianceController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
sub: "/Lotus/Language/Menu/Mailbox_AllianceInvite_Title",
|
sub: "/Lotus/Language/Menu/Mailbox_AllianceInvite_Title",
|
||||||
icon: ExportFlavour[getEffectiveAvatarImageType(senderInventory)].icon,
|
icon: ExportFlavour[senderInventory.ActiveAvatarImageType].icon,
|
||||||
contextInfo: alliance._id.toString(),
|
contextInfo: alliance._id.toString(),
|
||||||
highPriority: true,
|
highPriority: true,
|
||||||
acceptAction: "ALLIANCE_INVITE",
|
acceptAction: "ALLIANCE_INVITE",
|
||||||
|
|||||||
@ -1,16 +1,13 @@
|
|||||||
import { toMongoDate } from "../../helpers/inventoryHelpers.ts";
|
import { Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { Guild, GuildMember } from "../../models/guildModel.ts";
|
import { Account } from "@/src/models/loginModel";
|
||||||
import { Account } from "../../models/loginModel.ts";
|
import { fillInInventoryDataForGuildMember, hasGuildPermission } from "@/src/services/guildService";
|
||||||
import { addInventoryDataToFriendInfo, areFriends } from "../../services/friendService.ts";
|
import { createMessage } from "@/src/services/inboxService";
|
||||||
import { hasGuildPermission } from "../../services/guildService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { createMessage } from "../../services/inboxService.ts";
|
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
|
||||||
import { getEffectiveAvatarImageType, getInventory } from "../../services/inventoryService.ts";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "../../services/loginService.ts";
|
import { GuildPermission, IGuildMemberClient } from "@/src/types/guildTypes";
|
||||||
import type { IOid } from "../../types/commonTypes.ts";
|
import { logger } from "@/src/utils/logger";
|
||||||
import type { IGuildMemberClient } from "../../types/guildTypes.ts";
|
import { RequestHandler } from "express";
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
|
||||||
import { logger } from "../../utils/logger.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
import { ExportFlavour } from "warframe-public-export-plus";
|
import { ExportFlavour } from "warframe-public-export-plus";
|
||||||
|
|
||||||
export const addToGuildController: RequestHandler = async (req, res) => {
|
export const addToGuildController: RequestHandler = async (req, res) => {
|
||||||
@ -25,18 +22,15 @@ export const addToGuildController: RequestHandler = async (req, res) => {
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const senderAccount = await getAccountForRequest(req);
|
|
||||||
const inventory = await getInventory(account._id.toString(), "Settings");
|
const inventory = await getInventory(account._id.toString(), "Settings");
|
||||||
if (
|
// TODO: Also consider GIFT_MODE_FRIENDS once friends are implemented
|
||||||
inventory.Settings?.GuildInvRestriction == "GIFT_MODE_NONE" ||
|
if (inventory.Settings?.GuildInvRestriction == "GIFT_MODE_NONE") {
|
||||||
(inventory.Settings?.GuildInvRestriction == "GIFT_MODE_FRIENDS" &&
|
|
||||||
!(await areFriends(account._id, senderAccount._id)))
|
|
||||||
) {
|
|
||||||
res.status(400).json("Invite restricted");
|
res.status(400).json("Invite restricted");
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const guild = (await Guild.findById(payload.GuildId.$oid, "Name Ranks"))!;
|
const guild = (await Guild.findById(payload.GuildId.$oid, "Name Ranks"))!;
|
||||||
|
const senderAccount = await getAccountForRequest(req);
|
||||||
if (!(await hasGuildPermission(guild, senderAccount._id.toString(), GuildPermission.Recruiter))) {
|
if (!(await hasGuildPermission(guild, senderAccount._id.toString(), GuildPermission.Recruiter))) {
|
||||||
res.status(400).json("Invalid permission");
|
res.status(400).json("Invalid permission");
|
||||||
}
|
}
|
||||||
@ -65,7 +59,7 @@ export const addToGuildController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
sub: "/Lotus/Language/Menu/Mailbox_ClanInvite_Title",
|
sub: "/Lotus/Language/Menu/Mailbox_ClanInvite_Title",
|
||||||
icon: ExportFlavour[getEffectiveAvatarImageType(senderInventory)].icon,
|
icon: ExportFlavour[senderInventory.ActiveAvatarImageType].icon,
|
||||||
contextInfo: payload.GuildId.$oid,
|
contextInfo: payload.GuildId.$oid,
|
||||||
highPriority: true,
|
highPriority: true,
|
||||||
acceptAction: "GUILD_INVITE",
|
acceptAction: "GUILD_INVITE",
|
||||||
@ -77,11 +71,10 @@ export const addToGuildController: RequestHandler = async (req, res) => {
|
|||||||
const member: IGuildMemberClient = {
|
const member: IGuildMemberClient = {
|
||||||
_id: { $oid: account._id.toString() },
|
_id: { $oid: account._id.toString() },
|
||||||
DisplayName: account.DisplayName,
|
DisplayName: account.DisplayName,
|
||||||
LastLogin: toMongoDate(account.LastLogin),
|
|
||||||
Rank: 7,
|
Rank: 7,
|
||||||
Status: 2
|
Status: 2
|
||||||
};
|
};
|
||||||
await addInventoryDataToFriendInfo(member);
|
await fillInInventoryDataForGuildMember(member);
|
||||||
res.json({ NewMember: member });
|
res.json({ NewMember: member });
|
||||||
} else if ("RequestMsg" in payload) {
|
} else if ("RequestMsg" in payload) {
|
||||||
// Player applying to join a clan
|
// Player applying to join a clan
|
||||||
|
|||||||
@ -1,27 +0,0 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const adoptPetController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId, "KubrowPets");
|
|
||||||
const data = getJSONfromString<IAdoptPetRequest>(String(req.body));
|
|
||||||
const details = inventory.KubrowPets.id(data.petId)!.Details!;
|
|
||||||
details.Name = data.name;
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
petId: data.petId,
|
|
||||||
newName: data.name
|
|
||||||
} satisfies IAdoptPetResponse);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IAdoptPetRequest {
|
|
||||||
petId: string;
|
|
||||||
name: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IAdoptPetResponse {
|
|
||||||
petId: string;
|
|
||||||
newName: string;
|
|
||||||
}
|
|
||||||
@ -1,22 +0,0 @@
|
|||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import { getPersonalRooms } from "../../services/personalRoomsService.ts";
|
|
||||||
import type { 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;
|
|
||||||
}
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory, addMods } from "../../services/inventoryService.ts";
|
import { getInventory, addMods } from "@/src/services/inventoryService";
|
||||||
import type { IOid } from "../../types/commonTypes.ts";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
|
|
||||||
export const arcaneCommonController: RequestHandler = async (req, res) => {
|
export const arcaneCommonController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addMiscItems, getInventory } from "../../services/inventoryService.ts";
|
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
||||||
import type { IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { colorToShard, combineColors, shardToColor } from "../../helpers/shardHelper.ts";
|
import { colorToShard, combineColors, shardToColor } from "@/src/helpers/shardHelper";
|
||||||
|
|
||||||
export const archonFusionController: RequestHandler = async (req, res) => {
|
export const archonFusionController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,12 +1,11 @@
|
|||||||
import { fromOid, toOid } from "../../helpers/inventoryHelpers.ts";
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "../../helpers/rivenHelper.ts";
|
import { createVeiledRivenFingerprint, rivenRawToRealWeighted } from "@/src/helpers/rivenHelper";
|
||||||
import { addMiscItems, addMods, getInventory } from "../../services/inventoryService.ts";
|
import { addMiscItems, addMods, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getRandomElement, getRandomWeightedReward, getRandomWeightedRewardUc } from "../../services/rngService.ts";
|
import { getRandomElement, getRandomWeightedReward, getRandomWeightedRewardUc } from "@/src/services/rngService";
|
||||||
import type { IUpgradeFromClient } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import type { TRarity } from "warframe-public-export-plus";
|
import { ExportBoosterPacks, ExportUpgrades, TRarity } from "warframe-public-export-plus";
|
||||||
import { ExportBoosterPacks, ExportUpgrades } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const artifactTransmutationController: RequestHandler = async (req, res) => {
|
export const artifactTransmutationController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -25,11 +24,11 @@ export const artifactTransmutationController: RequestHandler = async (req, res)
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
payload.Consumed.forEach(upgrade => {
|
payload.Consumed.forEach(upgrade => {
|
||||||
inventory.Upgrades.pull({ _id: fromOid(upgrade.ItemId) });
|
inventory.Upgrades.pull({ _id: upgrade.ItemId.$oid });
|
||||||
});
|
});
|
||||||
|
|
||||||
const rawRivenType = getRandomRawRivenType();
|
const rawRivenType = getRandomRawRivenType();
|
||||||
const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType])!;
|
const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType]);
|
||||||
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
|
||||||
|
|
||||||
const upgradeIndex =
|
const upgradeIndex =
|
||||||
@ -58,8 +57,8 @@ export const artifactTransmutationController: RequestHandler = async (req, res)
|
|||||||
payload.Consumed.forEach(upgrade => {
|
payload.Consumed.forEach(upgrade => {
|
||||||
const meta = ExportUpgrades[upgrade.ItemType];
|
const meta = ExportUpgrades[upgrade.ItemType];
|
||||||
counts[meta.rarity] += upgrade.ItemCount;
|
counts[meta.rarity] += upgrade.ItemCount;
|
||||||
if (fromOid(upgrade.ItemId) != "000000000000000000000000") {
|
if (upgrade.ItemId.$oid != "000000000000000000000000") {
|
||||||
inventory.Upgrades.pull({ _id: fromOid(upgrade.ItemId) });
|
inventory.Upgrades.pull({ _id: upgrade.ItemId.$oid });
|
||||||
} else {
|
} else {
|
||||||
addMods(inventory, [
|
addMods(inventory, [
|
||||||
{
|
{
|
||||||
@ -129,14 +128,24 @@ const getRandomRawRivenType = (): string => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface IArtifactTransmutationRequest {
|
interface IArtifactTransmutationRequest {
|
||||||
Upgrade: IUpgradeFromClient;
|
Upgrade: IAgnosticUpgradeClient;
|
||||||
LevelDiff: number;
|
LevelDiff: number;
|
||||||
Consumed: IUpgradeFromClient[];
|
Consumed: IAgnosticUpgradeClient[];
|
||||||
Cost: number;
|
Cost: number;
|
||||||
FusionPointCost: number;
|
FusionPointCost: number;
|
||||||
RivenTransmute?: boolean;
|
RivenTransmute?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface IAgnosticUpgradeClient {
|
||||||
|
ItemType: string;
|
||||||
|
ItemId: IOid;
|
||||||
|
FromSKU: boolean;
|
||||||
|
UpgradeFingerprint: string;
|
||||||
|
PendingRerollFingerprint: string;
|
||||||
|
ItemCount: number;
|
||||||
|
LastAdded: IOid;
|
||||||
|
}
|
||||||
|
|
||||||
const specialModSets: string[][] = [
|
const specialModSets: string[][] = [
|
||||||
[
|
[
|
||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import type { IInventoryClient, IUpgradeClient } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { IInventoryClient, IUpgradeClient } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { addMods, getInventory } from "../../services/inventoryService.ts";
|
import { addMods, getInventory } from "@/src/services/inventoryService";
|
||||||
import { broadcastInventoryUpdate } from "../../services/wsService.ts";
|
import { config } from "@/src/services/configService";
|
||||||
|
|
||||||
export const artifactsController: RequestHandler = async (req, res) => {
|
export const artifactsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -24,6 +24,7 @@ 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({
|
||||||
@ -34,10 +35,10 @@ export const artifactsController: RequestHandler = async (req, res) => {
|
|||||||
addMods(inventory, [{ ItemType, ItemCount: -1 }]);
|
addMods(inventory, [{ ItemType, ItemCount: -1 }]);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!inventory.infiniteCredits) {
|
if (!config.infiniteCredits) {
|
||||||
inventory.RegularCredits -= Cost;
|
inventory.RegularCredits -= Cost;
|
||||||
}
|
}
|
||||||
if (!inventory.infiniteEndo) {
|
if (!config.infiniteEndo) {
|
||||||
inventory.FusionPoints -= FusionPointCost;
|
inventory.FusionPoints -= FusionPointCost;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -58,7 +59,6 @@ export const artifactsController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
res.send(itemId);
|
res.send(itemId);
|
||||||
broadcastInventoryUpdate(req);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IArtifactsRequest {
|
interface IArtifactsRequest {
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { GuildAd } from "../../models/guildModel.ts";
|
import { GuildAd } from "@/src/models/guildModel";
|
||||||
import { getGuildForRequestEx, hasGuildPermission } from "../../services/guildService.ts";
|
import { getGuildForRequestEx, hasGuildPermission } from "@/src/services/guildService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const cancelGuildAdvertisementController: RequestHandler = async (req, res) => {
|
export const cancelGuildAdvertisementController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,16 +1,10 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import {
|
import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, hasGuildPermission } from "@/src/services/guildService";
|
||||||
getDojoClient,
|
import { logger } from "@/src/utils/logger";
|
||||||
getGuildForRequestEx,
|
import { GuildPermission, IDojoComponentDatabase } from "@/src/types/guildTypes";
|
||||||
hasAccessToDojo,
|
|
||||||
hasGuildPermission
|
|
||||||
} from "../../services/guildService.ts";
|
|
||||||
import { logger } from "../../utils/logger.ts";
|
|
||||||
import type { IDojoComponentDatabase } from "../../types/guildTypes.ts";
|
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
export const changeDojoRootController: RequestHandler = async (req, res) => {
|
export const changeDojoRootController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { GuildMember } from "../../models/guildModel.ts";
|
import { GuildMember } from "@/src/models/guildModel";
|
||||||
import { getGuildForRequest, hasGuildPermissionEx } from "../../services/guildService.ts";
|
import { getGuildForRequest, hasGuildPermissionEx } from "@/src/services/guildService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const changeGuildRankController: RequestHandler = async (req, res) => {
|
export const changeGuildRankController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,12 +1,16 @@
|
|||||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
import { RequestHandler } from "express";
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const checkDailyMissionBonusController: RequestHandler = async (req, res) => {
|
const checkDailyMissionBonusController: RequestHandler = (_req, res) => {
|
||||||
const account = await getAccountForRequest(req);
|
const data = Buffer.from([
|
||||||
const today = Math.trunc(Date.now() / 86400000) * 86400;
|
0x44, 0x61, 0x69, 0x6c, 0x79, 0x4d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e, 0x42, 0x6f, 0x6e, 0x75, 0x73, 0x3a,
|
||||||
if (account.DailyFirstWinDate != today) {
|
0x31, 0x2d, 0x44, 0x61, 0x69, 0x6c, 0x79, 0x50, 0x56, 0x50, 0x57, 0x69, 0x6e, 0x42, 0x6f, 0x6e, 0x75, 0x73,
|
||||||
res.send("DailyMissionBonus:1-DailyPVPWinBonus:1\n");
|
0x3a, 0x31, 0x0a
|
||||||
} else {
|
]);
|
||||||
res.send("DailyMissionBonus:0-DailyPVPWinBonus:1\n");
|
res.writeHead(200, {
|
||||||
}
|
"Content-Type": "text/html",
|
||||||
|
"Content-Length": data.length
|
||||||
|
});
|
||||||
|
res.end(data);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export { checkDailyMissionBonusController };
|
||||||
|
|||||||
@ -1,53 +1,38 @@
|
|||||||
//this is a controller for the claimCompletedRecipe route
|
//this is a controller for the claimCompletedRecipe route
|
||||||
//it will claim a recipe for the user
|
//it will claim a recipe for the user
|
||||||
|
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { logger } from "../../utils/logger.ts";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { getRecipe } from "../../services/itemDataService.ts";
|
import { getRecipe } from "@/src/services/itemDataService";
|
||||||
import type { IOidWithLegacySupport } from "../../types/commonTypes.ts";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import type { TAccountDocument } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
|
||||||
import {
|
import {
|
||||||
getInventory,
|
getInventory,
|
||||||
updateCurrency,
|
updateCurrency,
|
||||||
addItem,
|
addItem,
|
||||||
addRecipes,
|
addRecipes,
|
||||||
occupySlot,
|
occupySlot,
|
||||||
combineInventoryChanges,
|
combineInventoryChanges
|
||||||
addKubrowPetPrint,
|
} from "@/src/services/inventoryService";
|
||||||
addPowerSuit,
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
addEquipment
|
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
} from "../../services/inventoryService.ts";
|
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import type { IPendingRecipeDatabase } from "../../types/inventoryTypes/inventoryTypes.ts";
|
|
||||||
import { InventorySlot } from "../../types/inventoryTypes/inventoryTypes.ts";
|
|
||||||
import { fromOid, toOid2 } from "../../helpers/inventoryHelpers.ts";
|
|
||||||
import type { TInventoryDatabaseDocument } from "../../models/inventoryModels/inventoryModel.ts";
|
|
||||||
import type { IRecipe } from "warframe-public-export-plus";
|
|
||||||
import type { IEquipmentClient } from "../../types/equipmentTypes.ts";
|
|
||||||
import { EquipmentFeatures, Status } from "../../types/equipmentTypes.ts";
|
|
||||||
|
|
||||||
interface IClaimCompletedRecipeRequest {
|
interface IClaimCompletedRecipeRequest {
|
||||||
RecipeIds: IOidWithLegacySupport[];
|
RecipeIds: IOid[];
|
||||||
}
|
|
||||||
|
|
||||||
interface IClaimCompletedRecipeResponse {
|
|
||||||
InventoryChanges: IInventoryChanges;
|
|
||||||
BrandedSuits?: IOidWithLegacySupport[];
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export const claimCompletedRecipeController: RequestHandler = async (req, res) => {
|
export const claimCompletedRecipeController: RequestHandler = async (req, res) => {
|
||||||
const claimCompletedRecipeRequest = getJSONfromString<IClaimCompletedRecipeRequest>(String(req.body));
|
const claimCompletedRecipeRequest = getJSONfromString<IClaimCompletedRecipeRequest>(String(req.body));
|
||||||
const account = await getAccountForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(account._id.toString());
|
if (!accountId) throw new Error("no account id");
|
||||||
const resp: IClaimCompletedRecipeResponse = {
|
|
||||||
InventoryChanges: {}
|
const inventory = await getInventory(accountId);
|
||||||
};
|
const pendingRecipe = inventory.PendingRecipes.id(claimCompletedRecipeRequest.RecipeIds[0].$oid);
|
||||||
for (const recipeId of claimCompletedRecipeRequest.RecipeIds) {
|
|
||||||
const pendingRecipe = inventory.PendingRecipes.id(fromOid(recipeId));
|
|
||||||
if (!pendingRecipe) {
|
if (!pendingRecipe) {
|
||||||
throw new Error(`no pending recipe found with id ${fromOid(recipeId)}`);
|
throw new Error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
//check recipe is indeed ready to be completed
|
//check recipe is indeed ready to be completed
|
||||||
@ -63,223 +48,9 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (req.query.cancel) {
|
if (req.query.cancel) {
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {
|
||||||
await refundRecipeIngredients(inventory, inventoryChanges, recipe, pendingRecipe);
|
...updateCurrency(inventory, recipe.buildPrice * -1, false)
|
||||||
await inventory.save();
|
};
|
||||||
res.json(inventoryChanges); // Not a bug: In the specific case of cancelling a recipe, InventoryChanges are expected to be the root.
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
await claimCompletedRecipe(account, inventory, recipe, pendingRecipe, resp, req.query.rush);
|
|
||||||
}
|
|
||||||
await inventory.save();
|
|
||||||
res.json(resp);
|
|
||||||
};
|
|
||||||
|
|
||||||
const claimCompletedRecipe = async (
|
|
||||||
account: TAccountDocument,
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
recipe: IRecipe,
|
|
||||||
pendingRecipe: IPendingRecipeDatabase,
|
|
||||||
resp: IClaimCompletedRecipeResponse,
|
|
||||||
rush: any
|
|
||||||
): Promise<void> => {
|
|
||||||
logger.debug("Claiming Recipe", { recipe, pendingRecipe });
|
|
||||||
|
|
||||||
if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
|
|
||||||
inventory.PendingSpectreLoadouts ??= [];
|
|
||||||
inventory.SpectreLoadouts ??= [];
|
|
||||||
|
|
||||||
const pendingLoadoutIndex = inventory.PendingSpectreLoadouts.findIndex(x => x.ItemType == recipe.resultType);
|
|
||||||
if (pendingLoadoutIndex != -1) {
|
|
||||||
const loadoutIndex = inventory.SpectreLoadouts.findIndex(x => x.ItemType == recipe.resultType);
|
|
||||||
if (loadoutIndex != -1) {
|
|
||||||
inventory.SpectreLoadouts.splice(loadoutIndex, 1);
|
|
||||||
}
|
|
||||||
logger.debug(
|
|
||||||
"moving spectre loadout from pending to active",
|
|
||||||
inventory.toJSON().PendingSpectreLoadouts![pendingLoadoutIndex]
|
|
||||||
);
|
|
||||||
inventory.SpectreLoadouts.push(inventory.PendingSpectreLoadouts[pendingLoadoutIndex]);
|
|
||||||
inventory.PendingSpectreLoadouts.splice(pendingLoadoutIndex, 1);
|
|
||||||
}
|
|
||||||
} else if (recipe.secretIngredientAction == "SIA_UNBRAND") {
|
|
||||||
inventory.BrandedSuits!.splice(
|
|
||||||
inventory.BrandedSuits!.findIndex(x => x.equals(pendingRecipe.SuitToUnbrand)),
|
|
||||||
1
|
|
||||||
);
|
|
||||||
resp.BrandedSuits = [toOid2(pendingRecipe.SuitToUnbrand!, account.BuildLabel)];
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipe.consumeOnUse) {
|
|
||||||
addRecipes(inventory, [
|
|
||||||
{
|
|
||||||
ItemType: pendingRecipe.ItemType,
|
|
||||||
ItemCount: -1
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (rush) {
|
|
||||||
const end = Math.trunc(pendingRecipe.CompletionDate.getTime() / 1000);
|
|
||||||
const start = end - recipe.buildTime;
|
|
||||||
const secondsElapsed = Math.trunc(Date.now() / 1000) - start;
|
|
||||||
const progress = secondsElapsed / recipe.buildTime;
|
|
||||||
logger.debug(`rushing recipe at ${Math.trunc(progress * 100)}% completion`);
|
|
||||||
const cost =
|
|
||||||
progress > 0.5 ? Math.round(recipe.skipBuildTimePrice * (1 - (progress - 0.5))) : recipe.skipBuildTimePrice;
|
|
||||||
combineInventoryChanges(resp.InventoryChanges, updateCurrency(inventory, cost, true));
|
|
||||||
}
|
|
||||||
|
|
||||||
if (recipe.secretIngredientAction == "SIA_CREATE_KUBROW") {
|
|
||||||
const pet = inventory.KubrowPets.id(pendingRecipe.KubrowPet!)!;
|
|
||||||
if (pet.Details!.HatchDate!.getTime() > Date.now()) {
|
|
||||||
pet.Details!.HatchDate = new Date();
|
|
||||||
}
|
|
||||||
let canSetActive = true;
|
|
||||||
for (const pet of inventory.KubrowPets) {
|
|
||||||
if (pet.Details!.Status == Status.StatusAvailable) {
|
|
||||||
canSetActive = false;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
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, resp.InventoryChanges);
|
|
||||||
} else if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
|
||||||
if (recipe.resultType == "/Lotus/Powersuits/Excalibur/ExcaliburUmbra") {
|
|
||||||
// Quite the special case here...
|
|
||||||
// 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];
|
|
||||||
resp.InventoryChanges.Upgrades ??= [];
|
|
||||||
resp.InventoryChanges.Upgrades.push(umbraModA, umbraModB, umbraModC, sacrificeModA, sacrificeModB);
|
|
||||||
|
|
||||||
await addPowerSuit(
|
|
||||||
inventory,
|
|
||||||
"/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
|
|
||||||
{
|
|
||||||
Configs: [
|
|
||||||
{
|
|
||||||
Upgrades: [
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
"",
|
|
||||||
umbraModA.ItemId.$oid,
|
|
||||||
umbraModB.ItemId.$oid,
|
|
||||||
umbraModC.ItemId.$oid
|
|
||||||
]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
XP: 900_000,
|
|
||||||
Features: EquipmentFeatures.DOUBLE_CAPACITY
|
|
||||||
},
|
|
||||||
resp.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
|
|
||||||
},
|
|
||||||
resp.InventoryChanges
|
|
||||||
);
|
|
||||||
inventory.XPInfo.push({
|
|
||||||
ItemType: "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
|
|
||||||
XP: 450_000
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
combineInventoryChanges(
|
|
||||||
resp.InventoryChanges,
|
|
||||||
await addItem(
|
|
||||||
inventory,
|
|
||||||
recipe.resultType,
|
|
||||||
recipe.num,
|
|
||||||
false,
|
|
||||||
undefined,
|
|
||||||
pendingRecipe.TargetFingerprint
|
|
||||||
)
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (
|
|
||||||
inventory.claimingBlueprintRefundsIngredients &&
|
|
||||||
recipe.secretIngredientAction != "SIA_CREATE_KUBROW" // Can't refund the egg
|
|
||||||
) {
|
|
||||||
await refundRecipeIngredients(inventory, resp.InventoryChanges, recipe, pendingRecipe);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const refundRecipeIngredients = async (
|
|
||||||
inventory: TInventoryDatabaseDocument,
|
|
||||||
inventoryChanges: IInventoryChanges,
|
|
||||||
recipe: IRecipe,
|
|
||||||
pendingRecipe: IPendingRecipeDatabase
|
|
||||||
): Promise<void> => {
|
|
||||||
updateCurrency(inventory, recipe.buildPrice * -1, false, inventoryChanges);
|
|
||||||
|
|
||||||
const equipmentIngredients = new Set();
|
const equipmentIngredients = new Set();
|
||||||
for (const category of ["LongGuns", "Pistols", "Melee"] as const) {
|
for (const category of ["LongGuns", "Pistols", "Melee"] as const) {
|
||||||
@ -304,4 +75,68 @@ const refundRecipeIngredients = async (
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await inventory.save();
|
||||||
|
res.json(inventoryChanges); // Not a bug: In the specific case of cancelling a recipe, InventoryChanges are expected to be the root.
|
||||||
|
} else {
|
||||||
|
logger.debug("Claiming Recipe", { recipe, pendingRecipe });
|
||||||
|
|
||||||
|
let BrandedSuits: undefined | IOid[];
|
||||||
|
if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
|
||||||
|
inventory.PendingSpectreLoadouts ??= [];
|
||||||
|
inventory.SpectreLoadouts ??= [];
|
||||||
|
|
||||||
|
const pendingLoadoutIndex = inventory.PendingSpectreLoadouts.findIndex(
|
||||||
|
x => x.ItemType == recipe.resultType
|
||||||
|
);
|
||||||
|
if (pendingLoadoutIndex != -1) {
|
||||||
|
const loadoutIndex = inventory.SpectreLoadouts.findIndex(x => x.ItemType == recipe.resultType);
|
||||||
|
if (loadoutIndex != -1) {
|
||||||
|
inventory.SpectreLoadouts.splice(loadoutIndex, 1);
|
||||||
|
}
|
||||||
|
logger.debug(
|
||||||
|
"moving spectre loadout from pending to active",
|
||||||
|
inventory.toJSON().PendingSpectreLoadouts![pendingLoadoutIndex]
|
||||||
|
);
|
||||||
|
inventory.SpectreLoadouts.push(inventory.PendingSpectreLoadouts[pendingLoadoutIndex]);
|
||||||
|
inventory.PendingSpectreLoadouts.splice(pendingLoadoutIndex, 1);
|
||||||
|
}
|
||||||
|
} else if (recipe.secretIngredientAction == "SIA_UNBRAND") {
|
||||||
|
inventory.BrandedSuits!.splice(
|
||||||
|
inventory.BrandedSuits!.findIndex(x => x.equals(pendingRecipe.SuitToUnbrand)),
|
||||||
|
1
|
||||||
|
);
|
||||||
|
BrandedSuits = [toOid(pendingRecipe.SuitToUnbrand!)];
|
||||||
|
}
|
||||||
|
|
||||||
|
let InventoryChanges: IInventoryChanges = {};
|
||||||
|
if (recipe.consumeOnUse) {
|
||||||
|
addRecipes(inventory, [
|
||||||
|
{
|
||||||
|
ItemType: pendingRecipe.ItemType,
|
||||||
|
ItemCount: -1
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
if (req.query.rush) {
|
||||||
|
const end = Math.trunc(pendingRecipe.CompletionDate.getTime() / 1000);
|
||||||
|
const start = end - recipe.buildTime;
|
||||||
|
const secondsElapsed = Math.trunc(Date.now() / 1000) - start;
|
||||||
|
const progress = secondsElapsed / recipe.buildTime;
|
||||||
|
logger.debug(`rushing recipe at ${Math.trunc(progress * 100)}% completion`);
|
||||||
|
const cost = Math.round(recipe.skipBuildTimePrice * (1 - (progress - 0.5)));
|
||||||
|
InventoryChanges = {
|
||||||
|
...InventoryChanges,
|
||||||
|
...updateCurrency(inventory, cost, true)
|
||||||
|
};
|
||||||
|
}
|
||||||
|
if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
||||||
|
InventoryChanges = {
|
||||||
|
...InventoryChanges,
|
||||||
|
...(await addItem(inventory, recipe.resultType, recipe.num, false))
|
||||||
|
};
|
||||||
|
}
|
||||||
|
await inventory.save();
|
||||||
|
res.json({ InventoryChanges, BrandedSuits });
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,35 +0,0 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
|
||||||
import { combineInventoryChanges, getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import { handleStoreItemAcquisition } from "../../services/purchaseService.ts";
|
|
||||||
import type { 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,6 +1,6 @@
|
|||||||
import { addFusionPoints, getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const claimLibraryDailyTaskRewardController: RequestHandler = async (req, res) => {
|
export const claimLibraryDailyTaskRewardController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -17,7 +17,7 @@ export const claimLibraryDailyTaskRewardController: RequestHandler = async (req,
|
|||||||
}
|
}
|
||||||
syndicate.Standing += rewardStanding;
|
syndicate.Standing += rewardStanding;
|
||||||
|
|
||||||
addFusionPoints(inventory, 80 * rewardQuantity);
|
inventory.FusionPoints += 80 * rewardQuantity;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const clearDialogueHistoryController: RequestHandler = async (req, res) => {
|
export const clearDialogueHistoryController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
// example req.body: {"NewEpisodeReward":true,"crossPlaySetting":"ENABLED"}
|
// example req.body: {"NewEpisodeReward":true,"crossPlaySetting":"ENABLED"}
|
||||||
export const clearNewEpisodeRewardController: RequestHandler = (_req, res) => {
|
export const clearNewEpisodeRewardController: RequestHandler = (_req, res) => {
|
||||||
|
|||||||
@ -1,37 +0,0 @@
|
|||||||
import { checkCalendarAutoAdvance, getCalendarProgress, getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import { handleStoreItemAcquisition } from "../../services/purchaseService.ts";
|
|
||||||
import { getWorldState } from "../../services/worldStateService.ts";
|
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
// GET request; query parameters: CompletedEventIdx=0&Iteration=4&Version=19&Season=CST_SUMMER
|
|
||||||
export const completeCalendarEventController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const calendarProgress = getCalendarProgress(inventory);
|
|
||||||
const currentSeason = getWorldState().KnownCalendarSeasons[0];
|
|
||||||
let inventoryChanges: IInventoryChanges = {};
|
|
||||||
const dayIndex = calendarProgress.SeasonProgress.LastCompletedDayIdx + 1;
|
|
||||||
const day = currentSeason.Days[dayIndex];
|
|
||||||
if (day.events.length != 0) {
|
|
||||||
if (day.events[0].type == "CET_CHALLENGE") {
|
|
||||||
throw new Error(`completeCalendarEvent should not be used for challenges`);
|
|
||||||
}
|
|
||||||
const selection = day.events[parseInt(req.query.CompletedEventIdx as string)];
|
|
||||||
if (selection.type == "CET_REWARD") {
|
|
||||||
inventoryChanges = (await handleStoreItemAcquisition(selection.reward!, inventory)).InventoryChanges;
|
|
||||||
} else if (selection.type == "CET_UPGRADE") {
|
|
||||||
calendarProgress.YearProgress.Upgrades.push(selection.upgrade!);
|
|
||||||
} else if (selection.type != "CET_PLOT") {
|
|
||||||
throw new Error(`unexpected selection type: ${selection.type}`);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
calendarProgress.SeasonProgress.LastCompletedDayIdx = dayIndex;
|
|
||||||
checkCalendarAutoAdvance(inventory, currentSeason);
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: inventoryChanges,
|
|
||||||
CalendarProgress: inventory.CalendarProgress
|
|
||||||
});
|
|
||||||
};
|
|
||||||
@ -1,10 +1,11 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addMiscItems, getInventory, updateCurrency } from "../../services/inventoryService.ts";
|
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import type { IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import type { IVeiledRivenFingerprint } from "../../helpers/rivenHelper.ts";
|
import { createUnveiledRivenFingerprint } 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);
|
||||||
@ -26,11 +27,10 @@ export const completeRandomModChallengeController: RequestHandler = async (req,
|
|||||||
inventoryChanges.MiscItems = miscItemChanges;
|
inventoryChanges.MiscItems = miscItemChanges;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Complete the riven challenge
|
// Update riven fingerprint to a randomised unveiled state
|
||||||
const upgrade = inventory.Upgrades.id(request.ItemId)!;
|
const upgrade = inventory.Upgrades.id(request.ItemId)!;
|
||||||
const fp = JSON.parse(upgrade.UpgradeFingerprint!) as IVeiledRivenFingerprint;
|
const meta = ExportUpgrades[upgrade.ItemType];
|
||||||
fp.challenge.Progress = fp.challenge.Required;
|
upgrade.UpgradeFingerprint = JSON.stringify(createUnveiledRivenFingerprint(meta));
|
||||||
upgrade.UpgradeFingerprint = JSON.stringify(fp);
|
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Alliance, AllianceMember, Guild, GuildMember } from "../../models/guildModel.ts";
|
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { getAllianceClient } from "../../services/guildService.ts";
|
import { getAllianceClient } from "@/src/services/guildService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const confirmAllianceInvitationController: RequestHandler = async (req, res) => {
|
export const confirmAllianceInvitationController: RequestHandler = async (req, res) => {
|
||||||
// Check requester is a warlord in their guild
|
// Check requester is a warlord in their guild
|
||||||
|
|||||||
@ -1,18 +1,12 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild, GuildMember } from "../../models/guildModel.ts";
|
import { Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { Account } from "../../models/loginModel.ts";
|
import { Account } from "@/src/models/loginModel";
|
||||||
import {
|
import { deleteGuild, getGuildClient, hasGuildPermission, removeDojoKeyItems } from "@/src/services/guildService";
|
||||||
deleteGuild,
|
import { addRecipes, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
|
||||||
getGuildClient,
|
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
|
||||||
giveClanKey,
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
hasGuildPermission,
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
removeDojoKeyItems
|
import { RequestHandler } from "express";
|
||||||
} from "../../services/guildService.ts";
|
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "../../services/loginService.ts";
|
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
// GET request: A player accepting an invite they got in their inbox.
|
// GET request: A player accepting an invite they got in their inbox.
|
||||||
@ -47,7 +41,14 @@ export const confirmGuildInvitationGetController: RequestHandler = async (req, r
|
|||||||
// Update inventory of new member
|
// Update inventory of new member
|
||||||
const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
|
const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
|
||||||
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
||||||
giveClanKey(inventory, inventoryChanges);
|
const recipeChanges = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addRecipes(inventory, recipeChanges);
|
||||||
|
combineInventoryChanges(inventoryChanges, { Recipes: recipeChanges });
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
const guild = (await Guild.findById(req.query.clanId as string))!;
|
const guild = (await Guild.findById(req.query.clanId as string))!;
|
||||||
@ -62,7 +63,7 @@ export const confirmGuildInvitationGetController: RequestHandler = async (req, r
|
|||||||
await guild.save();
|
await guild.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
...(await getGuildClient(guild, account)),
|
...(await getGuildClient(guild, account._id.toString())),
|
||||||
InventoryChanges: inventoryChanges
|
InventoryChanges: inventoryChanges
|
||||||
});
|
});
|
||||||
} else {
|
} else {
|
||||||
@ -95,9 +96,14 @@ export const confirmGuildInvitationPostController: RequestHandler = async (req,
|
|||||||
await GuildMember.deleteMany({ accountId: guildMember.accountId, status: 1 });
|
await GuildMember.deleteMany({ accountId: guildMember.accountId, status: 1 });
|
||||||
|
|
||||||
// Update inventory of new member
|
// Update inventory of new member
|
||||||
const inventory = await getInventory(guildMember.accountId.toString(), "GuildId LevelKeys Recipes");
|
const inventory = await getInventory(guildMember.accountId.toString(), "GuildId Recipes");
|
||||||
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
|
||||||
giveClanKey(inventory);
|
addRecipes(inventory, [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
]);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
// Add join to clan log
|
// Add join to clan log
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { toMongoDate } from "../../helpers/inventoryHelpers.ts";
|
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild } from "../../models/guildModel.ts";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
import { checkClanAscensionHasRequiredContributors } from "../../services/guildService.ts";
|
import { checkClanAscensionHasRequiredContributors } from "@/src/services/guildService";
|
||||||
import { addFusionPoints, getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
export const contributeGuildClassController: RequestHandler = async (req, res) => {
|
export const contributeGuildClassController: RequestHandler = async (req, res) => {
|
||||||
@ -36,7 +36,7 @@ export const contributeGuildClassController: RequestHandler = async (req, res) =
|
|||||||
|
|
||||||
// Either way, endo is given to the contributor.
|
// Either way, endo is given to the contributor.
|
||||||
const inventory = await getInventory(accountId, "FusionPoints");
|
const inventory = await getInventory(accountId, "FusionPoints");
|
||||||
addFusionPoints(inventory, guild.CeremonyEndo!);
|
inventory.FusionPoints += guild.CeremonyEndo!;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
|
|||||||
@ -1,6 +1,5 @@
|
|||||||
import type { TGuildDatabaseDocument } from "../../models/guildModel.ts";
|
import { GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
||||||
import { GuildMember } from "../../models/guildModel.ts";
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import type { TInventoryDatabaseDocument } from "../../models/inventoryModels/inventoryModel.ts";
|
|
||||||
import {
|
import {
|
||||||
addGuildMemberMiscItemContribution,
|
addGuildMemberMiscItemContribution,
|
||||||
getDojoClient,
|
getDojoClient,
|
||||||
@ -9,15 +8,14 @@ import {
|
|||||||
processDojoBuildMaterialsGathered,
|
processDojoBuildMaterialsGathered,
|
||||||
scaleRequiredCount,
|
scaleRequiredCount,
|
||||||
setDojoRoomLogFunded
|
setDojoRoomLogFunded
|
||||||
} from "../../services/guildService.ts";
|
} from "@/src/services/guildService";
|
||||||
import { addMiscItems, getInventory, updateCurrency } from "../../services/inventoryService.ts";
|
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { IDojoContributable, IGuildMemberDatabase } from "../../types/guildTypes.ts";
|
import { IDojoContributable, IGuildMemberDatabase } from "@/src/types/guildTypes";
|
||||||
import type { IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import type { IDojoBuild } from "warframe-public-export-plus";
|
import { ExportDojoRecipes, IDojoBuild } from "warframe-public-export-plus";
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
interface IContributeToDojoComponentRequest {
|
interface IContributeToDojoComponentRequest {
|
||||||
ComponentId: string;
|
ComponentId: string;
|
||||||
|
|||||||
@ -1,5 +1,10 @@
|
|||||||
import type { TGuildDatabaseDocument, TGuildMemberDatabaseDocument } from "../../models/guildModel.ts";
|
import {
|
||||||
import { Alliance, Guild, GuildMember } from "../../models/guildModel.ts";
|
Alliance,
|
||||||
|
Guild,
|
||||||
|
GuildMember,
|
||||||
|
TGuildDatabaseDocument,
|
||||||
|
TGuildMemberDatabaseDocument
|
||||||
|
} from "@/src/models/guildModel";
|
||||||
import {
|
import {
|
||||||
addGuildMemberMiscItemContribution,
|
addGuildMemberMiscItemContribution,
|
||||||
addGuildMemberShipDecoContribution,
|
addGuildMemberShipDecoContribution,
|
||||||
@ -7,18 +12,17 @@ import {
|
|||||||
addVaultMiscItems,
|
addVaultMiscItems,
|
||||||
addVaultShipDecos,
|
addVaultShipDecos,
|
||||||
getGuildForRequestEx
|
getGuildForRequestEx
|
||||||
} from "../../services/guildService.ts";
|
} from "@/src/services/guildService";
|
||||||
import {
|
import {
|
||||||
addFusionTreasures,
|
addFusionTreasures,
|
||||||
addMiscItems,
|
addMiscItems,
|
||||||
addShipDecorations,
|
addShipDecorations,
|
||||||
getInventory,
|
getInventory,
|
||||||
updateCurrency
|
updateCurrency
|
||||||
} from "../../services/inventoryService.ts";
|
} from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { ITypeCount } from "../../types/commonTypes.ts";
|
import { IFusionTreasure, IMiscItem, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import type { IFusionTreasure, IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { RequestHandler } from "express";
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const contributeToVaultController: RequestHandler = async (req, res) => {
|
export const contributeToVaultController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,10 +1,10 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Alliance, AllianceMember, Guild, GuildMember } from "../../models/guildModel.ts";
|
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { getAllianceClient } from "../../services/guildService.ts";
|
import { getAllianceClient } from "@/src/services/guildService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const createAllianceController: RequestHandler = async (req, res) => {
|
export const createAllianceController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,17 +1,16 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild, GuildMember } from "../../models/guildModel.ts";
|
import { Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { createUniqueClanName, getGuildClient, giveClanKey } from "../../services/guildService.ts";
|
import { createUniqueClanName, getGuildClient } from "@/src/services/guildService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { addRecipes, getInventory } from "@/src/services/inventoryService";
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
|
||||||
|
|
||||||
export const createGuildController: RequestHandler = async (req, res) => {
|
export const createGuildController: RequestHandler = async (req, res) => {
|
||||||
const account = await getAccountForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const payload = getJSONfromString<ICreateGuildRequest>(String(req.body));
|
const payload = getJSONfromString<ICreateGuildRequest>(String(req.body));
|
||||||
|
|
||||||
// Remove pending applications for this account
|
// Remove pending applications for this account
|
||||||
await GuildMember.deleteMany({ accountId: account._id, status: 1 });
|
await GuildMember.deleteMany({ accountId, status: 1 });
|
||||||
|
|
||||||
// Create guild on database
|
// Create guild on database
|
||||||
const guild = new Guild({
|
const guild = new Guild({
|
||||||
@ -21,21 +20,32 @@ export const createGuildController: RequestHandler = async (req, res) => {
|
|||||||
|
|
||||||
// Create guild member on database
|
// Create guild member on database
|
||||||
await GuildMember.insertOne({
|
await GuildMember.insertOne({
|
||||||
accountId: account._id,
|
accountId: accountId,
|
||||||
guildId: guild._id,
|
guildId: guild._id,
|
||||||
status: 0,
|
status: 0,
|
||||||
rank: 0
|
rank: 0
|
||||||
});
|
});
|
||||||
|
|
||||||
const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
|
const inventory = await getInventory(accountId, "GuildId Recipes");
|
||||||
inventory.GuildId = guild._id;
|
inventory.GuildId = guild._id;
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
addRecipes(inventory, [
|
||||||
giveClanKey(inventory, inventoryChanges);
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
]);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
...(await getGuildClient(guild, account)),
|
...(await getGuildClient(guild, accountId)),
|
||||||
InventoryChanges: inventoryChanges
|
InventoryChanges: {
|
||||||
|
Recipes: [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
]
|
||||||
|
}
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,17 +1,12 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { config } from "@/src/services/configService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
|
||||||
export const creditsController: RequestHandler = async (req, res) => {
|
export const creditsController: RequestHandler = async (req, res) => {
|
||||||
const inventory = (
|
const accountId = await getAccountIdForRequest(req);
|
||||||
await Promise.all([
|
|
||||||
getAccountIdForRequest(req),
|
const inventory = await getInventory(accountId, "RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits");
|
||||||
getInventory(
|
|
||||||
req.query.accountId as string,
|
|
||||||
"RegularCredits TradesRemaining PremiumCreditsFree PremiumCredits infiniteCredits infinitePlatinum"
|
|
||||||
)
|
|
||||||
])
|
|
||||||
)[1];
|
|
||||||
|
|
||||||
const response = {
|
const response = {
|
||||||
RegularCredits: inventory.RegularCredits,
|
RegularCredits: inventory.RegularCredits,
|
||||||
@ -20,10 +15,10 @@ export const creditsController: RequestHandler = async (req, res) => {
|
|||||||
PremiumCredits: inventory.PremiumCredits
|
PremiumCredits: inventory.PremiumCredits
|
||||||
};
|
};
|
||||||
|
|
||||||
if (inventory.infiniteCredits) {
|
if (config.infiniteCredits) {
|
||||||
response.RegularCredits = 999999999;
|
response.RegularCredits = 999999999;
|
||||||
}
|
}
|
||||||
if (inventory.infinitePlatinum) {
|
if (config.infinitePlatinum) {
|
||||||
response.PremiumCreditsFree = 0;
|
response.PremiumCreditsFree = 0;
|
||||||
response.PremiumCredits = 999999999;
|
response.PremiumCredits = 999999999;
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,22 +1,14 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import type { TInventoryDatabaseDocument } from "../../models/inventoryModels/inventoryModel.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { ICrewMemberClient } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import type { ICrewMemberClient } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { RequestHandler } from "express";
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
export const crewMembersController: RequestHandler = async (req, res) => {
|
export const crewMembersController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId, "CrewMembers NemesisHistory");
|
const inventory = await getInventory(accountId, "CrewMembers");
|
||||||
const data = getJSONfromString<ICrewMembersRequest>(String(req.body));
|
const data = getJSONfromString<ICrewMembersRequest>(String(req.body));
|
||||||
if (data.crewMember.SecondInCommand) {
|
|
||||||
clearOnCall(inventory);
|
|
||||||
}
|
|
||||||
if (data.crewMember.ItemId.$oid == "000000000000000000000000") {
|
|
||||||
const convertedNemesis = inventory.NemesisHistory!.find(x => x.fp == data.crewMember.NemesisFingerprint)!;
|
|
||||||
convertedNemesis.SecondInCommand = data.crewMember.SecondInCommand;
|
|
||||||
} else {
|
|
||||||
const dbCrewMember = inventory.CrewMembers.id(data.crewMember.ItemId.$oid)!;
|
const dbCrewMember = inventory.CrewMembers.id(data.crewMember.ItemId.$oid)!;
|
||||||
dbCrewMember.AssignedRole = data.crewMember.AssignedRole;
|
dbCrewMember.AssignedRole = data.crewMember.AssignedRole;
|
||||||
dbCrewMember.SkillEfficiency = data.crewMember.SkillEfficiency;
|
dbCrewMember.SkillEfficiency = data.crewMember.SkillEfficiency;
|
||||||
@ -24,7 +16,6 @@ export const crewMembersController: RequestHandler = async (req, res) => {
|
|||||||
dbCrewMember.WeaponId = new Types.ObjectId(data.crewMember.WeaponId.$oid);
|
dbCrewMember.WeaponId = new Types.ObjectId(data.crewMember.WeaponId.$oid);
|
||||||
dbCrewMember.Configs = data.crewMember.Configs;
|
dbCrewMember.Configs = data.crewMember.Configs;
|
||||||
dbCrewMember.SecondInCommand = data.crewMember.SecondInCommand;
|
dbCrewMember.SecondInCommand = data.crewMember.SecondInCommand;
|
||||||
}
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
crewMemberId: data.crewMember.ItemId.$oid,
|
crewMemberId: data.crewMember.ItemId.$oid,
|
||||||
@ -35,20 +26,3 @@ export const crewMembersController: RequestHandler = async (req, res) => {
|
|||||||
interface ICrewMembersRequest {
|
interface ICrewMembersRequest {
|
||||||
crewMember: ICrewMemberClient;
|
crewMember: ICrewMemberClient;
|
||||||
}
|
}
|
||||||
|
|
||||||
const clearOnCall = (inventory: TInventoryDatabaseDocument): void => {
|
|
||||||
for (const cm of inventory.CrewMembers) {
|
|
||||||
if (cm.SecondInCommand) {
|
|
||||||
cm.SecondInCommand = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
if (inventory.NemesisHistory) {
|
|
||||||
for (const cm of inventory.NemesisHistory) {
|
|
||||||
if (cm.SecondInCommand) {
|
|
||||||
cm.SecondInCommand = false;
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1,107 +0,0 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
|
||||||
import { addMiscItems, freeUpSlot, getInventory, updateCurrency } from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import type { IOid } from "../../types/commonTypes.ts";
|
|
||||||
import type { ICrewShipComponentFingerprint } from "../../types/inventoryTypes/inventoryTypes.ts";
|
|
||||||
import { InventorySlot } from "../../types/inventoryTypes/inventoryTypes.ts";
|
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
import { ExportCustoms, ExportDojoRecipes } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const crewShipFusionController: RequestHandler = async (req, res) => {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const payload = getJSONfromString<ICrewShipFusionRequest>(String(req.body));
|
|
||||||
|
|
||||||
const isWeapon = inventory.CrewShipWeapons.id(payload.PartA.$oid);
|
|
||||||
const itemA = isWeapon ?? inventory.CrewShipWeaponSkins.id(payload.PartA.$oid)!;
|
|
||||||
const category = isWeapon ? "CrewShipWeapons" : "CrewShipWeaponSkins";
|
|
||||||
const salvageCategory = isWeapon ? "CrewShipSalvagedWeapons" : "CrewShipSalvagedWeaponSkins";
|
|
||||||
const itemB = inventory[payload.SourceRecipe ? salvageCategory : category].id(payload.PartB.$oid)!;
|
|
||||||
const tierA = itemA.ItemType.charCodeAt(itemA.ItemType.length - 1) - 65;
|
|
||||||
const tierB = itemB.ItemType.charCodeAt(itemB.ItemType.length - 1) - 65;
|
|
||||||
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
|
||||||
|
|
||||||
// Charge partial repair cost if fusing with an identified but unrepaired part
|
|
||||||
if (payload.SourceRecipe) {
|
|
||||||
const recipe = ExportDojoRecipes.research[payload.SourceRecipe];
|
|
||||||
updateCurrency(inventory, Math.round(recipe.price * 0.4), false, inventoryChanges);
|
|
||||||
const miscItemChanges = recipe.ingredients.map(x => ({ ...x, ItemCount: Math.round(x.ItemCount * -0.4) }));
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
inventoryChanges.MiscItems = miscItemChanges;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Remove inferior item
|
|
||||||
if (payload.SourceRecipe) {
|
|
||||||
inventory[salvageCategory].pull({ _id: payload.PartB.$oid });
|
|
||||||
inventoryChanges.RemovedIdItems = [{ ItemId: payload.PartB }];
|
|
||||||
} else {
|
|
||||||
const inferiorId = tierA < tierB ? payload.PartA : payload.PartB;
|
|
||||||
inventory[category].pull({ _id: inferiorId.$oid });
|
|
||||||
inventoryChanges.RemovedIdItems = [{ ItemId: inferiorId }];
|
|
||||||
freeUpSlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS);
|
|
||||||
inventoryChanges[InventorySlot.RJ_COMPONENT_AND_ARMAMENTS] = { count: -1, platinum: 0, Slots: 1 };
|
|
||||||
}
|
|
||||||
|
|
||||||
// Upgrade superior item
|
|
||||||
const superiorItem = tierA < tierB ? itemB : itemA;
|
|
||||||
const inferiorItem = tierA < tierB ? itemA : itemB;
|
|
||||||
const fingerprint: ICrewShipComponentFingerprint = JSON.parse(
|
|
||||||
superiorItem.UpgradeFingerprint!
|
|
||||||
) as ICrewShipComponentFingerprint;
|
|
||||||
const inferiorFingerprint: ICrewShipComponentFingerprint = inferiorItem.UpgradeFingerprint
|
|
||||||
? (JSON.parse(inferiorItem.UpgradeFingerprint) as ICrewShipComponentFingerprint)
|
|
||||||
: { compat: "", buffs: [] };
|
|
||||||
if (isWeapon) {
|
|
||||||
for (let i = 0; i != fingerprint.buffs.length; ++i) {
|
|
||||||
const buffA = fingerprint.buffs[i];
|
|
||||||
const buffB = i < inferiorFingerprint.buffs.length ? inferiorFingerprint.buffs[i] : undefined;
|
|
||||||
const fvalA = buffA.Value / 0x3fffffff;
|
|
||||||
const fvalB = (buffB?.Value ?? 0) / 0x3fffffff;
|
|
||||||
const percA = 0.3 + fvalA * (0.6 - 0.3);
|
|
||||||
const percB = 0.3 + fvalB * (0.6 - 0.3);
|
|
||||||
const newPerc = Math.min(0.6, Math.max(percA, percB) * FUSE_MULTIPLIERS[Math.abs(tierA - tierB)]);
|
|
||||||
const newFval = (newPerc - 0.3) / (0.6 - 0.3);
|
|
||||||
buffA.Value = Math.trunc(newFval * 0x3fffffff);
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
const superiorMeta = ExportCustoms[superiorItem.ItemType].randomisedUpgrades ?? [];
|
|
||||||
const inferiorMeta = ExportCustoms[inferiorItem.ItemType].randomisedUpgrades ?? [];
|
|
||||||
for (let i = 0; i != inferiorFingerprint.buffs.length; ++i) {
|
|
||||||
const buffA = fingerprint.buffs[i];
|
|
||||||
const buffB = inferiorFingerprint.buffs[i];
|
|
||||||
const fvalA = buffA.Value / 0x3fffffff;
|
|
||||||
const fvalB = buffB.Value / 0x3fffffff;
|
|
||||||
const rangeA = superiorMeta[i].range;
|
|
||||||
const rangeB = inferiorMeta[i].range;
|
|
||||||
const percA = rangeA[0] + fvalA * (rangeA[1] - rangeA[0]);
|
|
||||||
const percB = rangeB[0] + fvalB * (rangeB[1] - rangeB[0]);
|
|
||||||
const newPerc = Math.min(rangeA[1], Math.max(percA, percB) * FUSE_MULTIPLIERS[Math.abs(tierA - tierB)]);
|
|
||||||
const newFval = (newPerc - rangeA[0]) / (rangeA[1] - rangeA[0]);
|
|
||||||
buffA.Value = Math.trunc(newFval * 0x3fffffff);
|
|
||||||
}
|
|
||||||
if (inferiorFingerprint.SubroutineIndex !== undefined) {
|
|
||||||
const useSuperiorSubroutine = tierA < tierB ? !payload.UseSubroutineA : payload.UseSubroutineA;
|
|
||||||
if (!useSuperiorSubroutine) {
|
|
||||||
fingerprint.SubroutineIndex = inferiorFingerprint.SubroutineIndex;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
superiorItem.UpgradeFingerprint = JSON.stringify(fingerprint);
|
|
||||||
inventoryChanges[category] = [superiorItem.toJSON() as any];
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: inventoryChanges
|
|
||||||
});
|
|
||||||
};
|
|
||||||
|
|
||||||
interface ICrewShipFusionRequest {
|
|
||||||
PartA: IOid;
|
|
||||||
PartB: IOid;
|
|
||||||
SourceRecipe: string;
|
|
||||||
UseSubroutineA: boolean;
|
|
||||||
}
|
|
||||||
|
|
||||||
const FUSE_MULTIPLIERS = [1.1, 1.05, 1.02];
|
|
||||||
@ -3,19 +3,16 @@ import {
|
|||||||
addCrewShipRawSalvage,
|
addCrewShipRawSalvage,
|
||||||
getInventory,
|
getInventory,
|
||||||
addEquipment
|
addEquipment
|
||||||
} from "../../services/inventoryService.ts";
|
} from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import type {
|
import { ICrewShipComponentFingerprint, IInnateDamageFingerprint } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
ICrewShipComponentFingerprint,
|
|
||||||
IInnateDamageFingerprint
|
|
||||||
} from "../../types/inventoryTypes/inventoryTypes.ts";
|
|
||||||
import { ExportCustoms, ExportRailjackWeapons, ExportUpgrades } from "warframe-public-export-plus";
|
import { ExportCustoms, ExportRailjackWeapons, ExportUpgrades } from "warframe-public-export-plus";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { getRandomInt } from "../../services/rngService.ts";
|
import { getRandomInt } from "@/src/services/rngService";
|
||||||
import type { IFingerprintStat } from "../../helpers/rivenHelper.ts";
|
import { IFingerprintStat } from "@/src/helpers/rivenHelper";
|
||||||
import type { IEquipmentDatabase } from "../../types/equipmentTypes.ts";
|
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
|
|
||||||
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
|
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -65,7 +62,14 @@ export const crewShipIdentifySalvageController: RequestHandler = async (req, res
|
|||||||
} satisfies IInnateDamageFingerprint)
|
} satisfies IInnateDamageFingerprint)
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
addEquipment(inventory, "CrewShipSalvagedWeapons", payload.ItemType, defaultOverwrites, inventoryChanges);
|
addEquipment(
|
||||||
|
inventory,
|
||||||
|
"CrewShipSalvagedWeapons",
|
||||||
|
payload.ItemType,
|
||||||
|
undefined,
|
||||||
|
inventoryChanges,
|
||||||
|
defaultOverwrites
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inventoryChanges.CrewShipRawSalvage = [
|
inventoryChanges.CrewShipRawSalvage = [
|
||||||
|
|||||||
@ -1,15 +1,12 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Guild } from "../../models/guildModel.ts";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
import { hasAccessToDojo, hasGuildPermission } from "../../services/guildService.ts";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { getAccountForRequest, getAccountIdForRequest } from "../../services/loginService.ts";
|
import { RequestHandler } from "express";
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
|
||||||
import { logger } from "../../utils/logger.ts";
|
|
||||||
import type { 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 Ranks"))!;
|
const guild = (await Guild.findById(data.g, "DojoComponents"))!;
|
||||||
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({
|
||||||
@ -37,19 +34,6 @@ 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)}`);
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import { getGuildForRequest, hasGuildPermission } from "../../services/guildService.ts";
|
import { getGuildForRequest, hasGuildPermission } from "@/src/services/guildService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { IGuildRank } from "../../types/guildTypes.ts";
|
import { GuildPermission, IGuildRank } from "@/src/types/guildTypes";
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
import { RequestHandler } from "express";
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const customizeGuildRanksController: RequestHandler = async (req, res) => {
|
export const customizeGuildRanksController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { AllianceMember, GuildMember } from "../../models/guildModel.ts";
|
import { AllianceMember, GuildMember } from "@/src/models/guildModel";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const declineAllianceInviteController: RequestHandler = async (req, res) => {
|
export const declineAllianceInviteController: RequestHandler = async (req, res) => {
|
||||||
// Check requester is a warlord in their guild
|
// Check requester is a warlord in their guild
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
import { GuildMember } from "../../models/guildModel.ts";
|
import { GuildMember } from "@/src/models/guildModel";
|
||||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const declineGuildInviteController: RequestHandler = async (req, res) => {
|
export const declineGuildInviteController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountForRequest(req);
|
const accountId = await getAccountForRequest(req);
|
||||||
|
|||||||
@ -1,5 +1,5 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { deleteSession } from "../../managers/sessionManager.ts";
|
import { deleteSession } from "@/src/managers/sessionManager";
|
||||||
|
|
||||||
const deleteSessionController: RequestHandler = (_req, res) => {
|
const deleteSessionController: RequestHandler = (_req, res) => {
|
||||||
deleteSession(_req.query.sessionId as string);
|
deleteSession(_req.query.sessionId as string);
|
||||||
|
|||||||
@ -3,14 +3,12 @@ import {
|
|||||||
getGuildForRequestEx,
|
getGuildForRequestEx,
|
||||||
hasAccessToDojo,
|
hasAccessToDojo,
|
||||||
hasGuildPermission,
|
hasGuildPermission,
|
||||||
refundDojoDeco,
|
|
||||||
removeDojoDeco
|
removeDojoDeco
|
||||||
} from "../../services/guildService.ts";
|
} from "@/src/services/guildService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
import { logger } from "../../utils/logger.ts";
|
import { RequestHandler } from "express";
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const destroyDojoDecoController: RequestHandler = async (req, res) => {
|
export const destroyDojoDecoController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -20,20 +18,9 @@ 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 | IClearObstacleCourseRequest;
|
const request = JSON.parse(String(req.body)) as IDestroyDojoDecoRequest;
|
||||||
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));
|
||||||
@ -44,8 +31,3 @@ interface IDestroyDojoDecoRequest {
|
|||||||
ComponentId: string;
|
ComponentId: string;
|
||||||
DecoId: string;
|
DecoId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IClearObstacleCourseRequest {
|
|
||||||
ComponentId: string;
|
|
||||||
Act: "cObst" | "maybesomethingelsewedontknowabout";
|
|
||||||
}
|
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { Alliance, AllianceMember, Guild, GuildMember } from "../../models/guildModel.ts";
|
import { Alliance, AllianceMember, Guild, GuildMember } from "@/src/models/guildModel";
|
||||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
import { GuildPermission } from "../../types/guildTypes.ts";
|
import { GuildPermission } from "@/src/types/guildTypes";
|
||||||
import { parallelForeach } from "../../utils/async-utils.ts";
|
import { parallelForeach } from "@/src/utils/async-utils";
|
||||||
import { logger } from "../../utils/logger.ts";
|
import { logger } from "@/src/utils/logger";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const divvyAllianceVaultController: RequestHandler = async (req, res) => {
|
export const divvyAllianceVaultController: RequestHandler = async (req, res) => {
|
||||||
// Afaict, there's no way to put anything other than credits in the alliance vault (anymore?), so just no-op if this is not a request to divvy credits.
|
// Afaict, there's no way to put anything other than credits in the alliance vault (anymore?), so just no-op if this is not a request to divvy credits.
|
||||||
|
|||||||
@ -1,17 +1,10 @@
|
|||||||
import type { TGuildDatabaseDocument } from "../../models/guildModel.ts";
|
import { GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
|
||||||
import { GuildMember } from "../../models/guildModel.ts";
|
import { getDojoClient, getGuildForRequestEx, hasAccessToDojo, scaleRequiredCount } from "@/src/services/guildService";
|
||||||
import {
|
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
getDojoClient,
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
getGuildForRequestEx,
|
import { IDojoContributable } from "@/src/types/guildTypes";
|
||||||
hasAccessToDojo,
|
import { RequestHandler } from "express";
|
||||||
scaleRequiredCount
|
import { ExportDojoRecipes, IDojoBuild } from "warframe-public-export-plus";
|
||||||
} from "../../services/guildService.ts";
|
|
||||||
import { getInventory, updateCurrency } from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import type { IDojoContributable } from "../../types/guildTypes.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
import type { IDojoBuild } from "warframe-public-export-plus";
|
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
interface IDojoComponentRushRequest {
|
interface IDojoComponentRushRequest {
|
||||||
DecoType?: string;
|
DecoType?: string;
|
||||||
|
|||||||
@ -1,4 +1,4 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
// Arbiter Dojo endpoints, not really used by us as we don't provide a ContentURL.
|
// Arbiter Dojo endpoints, not really used by us as we don't provide a ContentURL.
|
||||||
|
|
||||||
|
|||||||
@ -1,12 +1,13 @@
|
|||||||
import { toMongoDate, toOid } from "../../helpers/inventoryHelpers.ts";
|
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { addMiscItems, getInventory } from "../../services/inventoryService.ts";
|
import { config } from "@/src/services/configService";
|
||||||
import { fromStoreItem } from "../../services/itemDataService.ts";
|
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { fromStoreItem } from "@/src/services/itemDataService";
|
||||||
import { getRandomInt, getRandomWeightedRewardUc } from "../../services/rngService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { IMongoDate, IOid } from "../../types/commonTypes.ts";
|
import { getRandomInt, getRandomWeightedRewardUc } from "@/src/services/rngService";
|
||||||
import type { IDroneClient } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { IMongoDate, IOid } from "@/src/types/commonTypes";
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
import { IDroneClient } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
import { ExportDrones, ExportResources, ExportSystems } from "warframe-public-export-plus";
|
import { ExportDrones, ExportResources, ExportSystems } from "warframe-public-export-plus";
|
||||||
|
|
||||||
export const dronesController: RequestHandler = async (req, res) => {
|
export const dronesController: RequestHandler = async (req, res) => {
|
||||||
@ -38,13 +39,10 @@ export const dronesController: RequestHandler = async (req, res) => {
|
|||||||
ActiveDrones: activeDrones
|
ActiveDrones: activeDrones
|
||||||
});
|
});
|
||||||
} else if ("droneId" in req.query && "systemIndex" in req.query) {
|
} else if ("droneId" in req.query && "systemIndex" in req.query) {
|
||||||
const inventory = await getInventory(
|
const inventory = await getInventory(accountId, "Drones");
|
||||||
accountId,
|
|
||||||
"Drones instantResourceExtractorDrones noResourceExtractorDronesDamage"
|
|
||||||
);
|
|
||||||
const drone = inventory.Drones.id(req.query.droneId as string)!;
|
const drone = inventory.Drones.id(req.query.droneId as string)!;
|
||||||
const droneMeta = ExportDrones[drone.ItemType];
|
const droneMeta = ExportDrones[drone.ItemType];
|
||||||
drone.DeployTime = inventory.instantResourceExtractorDrones ? new Date(0) : new Date();
|
drone.DeployTime = config.instantResourceExtractorDrones ? new Date(0) : new Date();
|
||||||
if (drone.RepairStart) {
|
if (drone.RepairStart) {
|
||||||
const repairMinutes = (Date.now() - drone.RepairStart.getTime()) / 60_000;
|
const repairMinutes = (Date.now() - drone.RepairStart.getTime()) / 60_000;
|
||||||
const hpPerMinute = droneMeta.repairRate / 60;
|
const hpPerMinute = droneMeta.repairRate / 60;
|
||||||
@ -53,11 +51,11 @@ export const dronesController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
drone.System = parseInt(req.query.systemIndex as string);
|
drone.System = parseInt(req.query.systemIndex as string);
|
||||||
const system = ExportSystems[drone.System - 1];
|
const system = ExportSystems[drone.System - 1];
|
||||||
drone.DamageTime = inventory.instantResourceExtractorDrones
|
drone.DamageTime = config.instantResourceExtractorDrones
|
||||||
? new Date()
|
? new Date()
|
||||||
: new Date(Date.now() + getRandomInt(3 * 3600 * 1000, 4 * 3600 * 1000));
|
: new Date(Date.now() + getRandomInt(3 * 3600 * 1000, 4 * 3600 * 1000));
|
||||||
drone.PendingDamage =
|
drone.PendingDamage =
|
||||||
!inventory.noResourceExtractorDronesDamage && Math.random() < system.damageChance
|
!config.noResourceExtractorDronesDamage && Math.random() < system.damageChance
|
||||||
? getRandomInt(system.droneDamage.minValue, system.droneDamage.maxValue)
|
? getRandomInt(system.droneDamage.minValue, system.droneDamage.maxValue)
|
||||||
: 0;
|
: 0;
|
||||||
const resource = getRandomWeightedRewardUc(system.resources, droneMeta.probabilities)!;
|
const resource = getRandomWeightedRewardUc(system.resources, droneMeta.probabilities)!;
|
||||||
@ -74,7 +72,7 @@ export const dronesController: RequestHandler = async (req, res) => {
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
drone.ResourceCount = droneMeta.binCapacity * droneMeta.capacityMultipliers[resource.Rarity];
|
drone.ResourceCount = 1;
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({});
|
res.json({});
|
||||||
|
|||||||
@ -1,534 +1,60 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { combineInventoryChanges, getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import type {
|
import { TEndlessXpCategory } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
IEndlessXpReward,
|
|
||||||
IInventoryClient,
|
|
||||||
TEndlessXpCategory
|
|
||||||
} from "../../types/inventoryTypes/inventoryTypes.ts";
|
|
||||||
import { logger } from "../../utils/logger.ts";
|
|
||||||
import type { ICountedStoreItem } from "warframe-public-export-plus";
|
|
||||||
import { ExportRewards } from "warframe-public-export-plus";
|
|
||||||
import { getRandomElement } from "../../services/rngService.ts";
|
|
||||||
import { handleStoreItemAcquisition } from "../../services/purchaseService.ts";
|
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
|
||||||
|
|
||||||
export const endlessXpController: RequestHandler = async (req, res) => {
|
export const endlessXpController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId);
|
||||||
const payload = getJSONfromString<IEndlessXpRequest>(String(req.body));
|
const payload = getJSONfromString<IEndlessXpRequest>(String(req.body));
|
||||||
if (payload.Mode == "r") {
|
|
||||||
const inventory = await getInventory(accountId, "EndlessXP");
|
|
||||||
inventory.EndlessXP ??= [];
|
inventory.EndlessXP ??= [];
|
||||||
let entry = inventory.EndlessXP.find(x => x.Category == payload.Category);
|
const entry = inventory.EndlessXP.find(x => x.Category == payload.Category);
|
||||||
if (!entry) {
|
if (entry) {
|
||||||
entry = {
|
entry.Choices = payload.Choices;
|
||||||
|
} else {
|
||||||
|
inventory.EndlessXP.push({
|
||||||
|
Category: payload.Category,
|
||||||
|
Choices: payload.Choices
|
||||||
|
});
|
||||||
|
}
|
||||||
|
await inventory.save();
|
||||||
|
|
||||||
|
res.json({
|
||||||
|
NewProgress: {
|
||||||
Category: payload.Category,
|
Category: payload.Category,
|
||||||
Earn: 0,
|
Earn: 0,
|
||||||
Claim: 0,
|
Claim: 0,
|
||||||
|
BonusAvailable: {
|
||||||
|
$date: {
|
||||||
|
$numberLong: "9999999999999"
|
||||||
|
}
|
||||||
|
},
|
||||||
|
Expiry: {
|
||||||
|
$date: {
|
||||||
|
$numberLong: "9999999999999"
|
||||||
|
}
|
||||||
|
},
|
||||||
Choices: payload.Choices,
|
Choices: payload.Choices,
|
||||||
PendingRewards: []
|
PendingRewards: [
|
||||||
};
|
|
||||||
inventory.EndlessXP.push(entry);
|
|
||||||
}
|
|
||||||
|
|
||||||
const weekStart = 1734307200_000 + Math.trunc((Date.now() - 1734307200_000) / 604800000) * 604800000;
|
|
||||||
const weekEnd = weekStart + 604800000;
|
|
||||||
|
|
||||||
entry.Earn = 0;
|
|
||||||
entry.Claim = 0;
|
|
||||||
entry.BonusAvailable = new Date(weekStart);
|
|
||||||
entry.Expiry = new Date(weekEnd);
|
|
||||||
entry.Choices = payload.Choices;
|
|
||||||
entry.PendingRewards =
|
|
||||||
payload.Category == "EXC_HARD"
|
|
||||||
? generateHardModeRewards(payload.Choices)
|
|
||||||
: generateNormalModeRewards(payload.Choices);
|
|
||||||
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
NewProgress: inventory.toJSON<IInventoryClient>().EndlessXP!.find(x => x.Category == payload.Category)!
|
|
||||||
});
|
|
||||||
} else if (payload.Mode == "c") {
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
const entry = inventory.EndlessXP!.find(x => x.Category == payload.Category)!;
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
|
||||||
for (const reward of entry.PendingRewards) {
|
|
||||||
if (entry.Claim < reward.RequiredTotalXp && reward.RequiredTotalXp <= entry.Earn) {
|
|
||||||
combineInventoryChanges(
|
|
||||||
inventoryChanges,
|
|
||||||
(
|
|
||||||
await handleStoreItemAcquisition(
|
|
||||||
reward.Rewards[0].StoreItem,
|
|
||||||
inventory,
|
|
||||||
reward.Rewards[0].ItemCount
|
|
||||||
)
|
|
||||||
).InventoryChanges
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
entry.Claim = entry.Earn;
|
|
||||||
await inventory.save();
|
|
||||||
res.json({
|
|
||||||
InventoryChanges: inventoryChanges,
|
|
||||||
ClaimedXp: entry.Claim
|
|
||||||
});
|
|
||||||
} else {
|
|
||||||
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
|
||||||
throw new Error(`unexpected endlessXp mode: ${payload.Mode}`);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
type IEndlessXpRequest =
|
|
||||||
| {
|
|
||||||
Mode: "r";
|
|
||||||
Category: TEndlessXpCategory;
|
|
||||||
Choices: string[];
|
|
||||||
}
|
|
||||||
| {
|
|
||||||
Mode: "c" | "something else";
|
|
||||||
Category: TEndlessXpCategory;
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateRandomRewards = (deckName: string): ICountedStoreItem[] => {
|
|
||||||
const reward = getRandomElement(ExportRewards[deckName][0])!;
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
StoreItem: reward.type,
|
|
||||||
ItemCount: reward.itemCount
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|
||||||
const normalModeChosenRewards: Record<string, string[]> = {
|
|
||||||
Excalibur: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ExcaliburHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ExcaliburChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Excalibur/RadialJavelinAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ExcaliburSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ExcaliburBlueprint"
|
|
||||||
],
|
|
||||||
Trinity: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrinityHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrinityChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Trinity/EnergyVampireAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrinitySystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrinityBlueprint"
|
|
||||||
],
|
|
||||||
Ember: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/EmberHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/EmberChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Ember/WorldOnFireAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/EmberSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/EmberBlueprint"
|
|
||||||
],
|
|
||||||
Loki: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/LOKIHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/LOKIChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Loki/InvisibilityAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/LOKISystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/LOKIBlueprint"
|
|
||||||
],
|
|
||||||
Mag: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Mag/CrushAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagBlueprint"
|
|
||||||
],
|
|
||||||
Rhino: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RhinoHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RhinoChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Rhino/RhinoChargeAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RhinoSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RhinoBlueprint"
|
|
||||||
],
|
|
||||||
Ash: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/AshHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/AshChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Ninja/GlaiveAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/AshSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/AshBlueprint"
|
|
||||||
],
|
|
||||||
Frost: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FrostHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FrostChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Frost/IceShieldAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FrostSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FrostBlueprint"
|
|
||||||
],
|
|
||||||
Nyx: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NyxHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NyxChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Jade/SelfBulletAttractorAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NyxSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NyxBlueprint"
|
|
||||||
],
|
|
||||||
Saryn: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/SarynHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/SarynChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Saryn/PoisonAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/SarynSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/SarynBlueprint"
|
|
||||||
],
|
|
||||||
Vauban: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Trapper/LevTrapAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TrapperBlueprint"
|
|
||||||
],
|
|
||||||
Nova: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NovaHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NovaChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/AntiMatter/MolecularPrimeAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NovaSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NovaBlueprint"
|
|
||||||
],
|
|
||||||
Nekros: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NecroHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NecroChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Necro/CloneTheDeadAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NecroSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NecroBlueprint"
|
|
||||||
],
|
|
||||||
Valkyr: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BerserkerHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BerserkerChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Berserker/IntimidateAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BerserkerSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BerserkerBlueprint"
|
|
||||||
],
|
|
||||||
Oberon: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PaladinHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PaladinChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Paladin/RegenerationAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PaladinSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PaladinBlueprint"
|
|
||||||
],
|
|
||||||
Hydroid: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HydroidHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HydroidChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Pirate/CannonBarrageAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HydroidSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HydroidBlueprint"
|
|
||||||
],
|
|
||||||
Mirage: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HarlequinHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HarlequinChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Harlequin/LightAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HarlequinSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/HarlequinBlueprint"
|
|
||||||
],
|
|
||||||
Limbo: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagicianHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagicianChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Magician/TearInSpaceAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagicianSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MagicianBlueprint"
|
|
||||||
],
|
|
||||||
Mesa: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GunslingerHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GunslingerChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Cowgirl/GunFuPvPAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GunslingerSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GunslingerBlueprint"
|
|
||||||
],
|
|
||||||
Chroma: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Dragon/DragonLuckAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/ChromaBlueprint"
|
|
||||||
],
|
|
||||||
Atlas: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BrawlerHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BrawlerChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Brawler/BrawlerPassiveAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BrawlerSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/BrawlerBlueprint"
|
|
||||||
],
|
|
||||||
Ivara: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RangerHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RangerChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Ranger/RangerStealAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RangerSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RangerBlueprint"
|
|
||||||
],
|
|
||||||
Inaros: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MummyHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MummyChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Sandman/SandmanSwarmAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MummySystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/MummyBlueprint"
|
|
||||||
],
|
|
||||||
Titania: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FairyHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FairyChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Fairy/FairyFlightAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FairySystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/FairyBlueprint"
|
|
||||||
],
|
|
||||||
Nidus: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NidusHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NidusChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Infestation/InfestPodsAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NidusSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/NidusBlueprint"
|
|
||||||
],
|
|
||||||
Octavia: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/OctaviaHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/OctaviaChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Bard/BardCharmAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/OctaviaSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/OctaviaBlueprint"
|
|
||||||
],
|
|
||||||
Harrow: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PriestHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PriestChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Priest/PriestPactAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PriestSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PriestBlueprint"
|
|
||||||
],
|
|
||||||
Gara: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GlassHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GlassChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Glass/GlassFragmentAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GlassSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GlassBlueprint"
|
|
||||||
],
|
|
||||||
Khora: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/KhoraHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/KhoraChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Khora/KhoraCrackAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/KhoraSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/KhoraBlueprint"
|
|
||||||
],
|
|
||||||
Revenant: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RevenantHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RevenantChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Revenant/RevenantMarkAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RevenantSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/RevenantBlueprint"
|
|
||||||
],
|
|
||||||
Garuda: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GarudaHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GarudaChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Garuda/GarudaUnstoppableAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GarudaSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/GarudaBlueprint"
|
|
||||||
],
|
|
||||||
Baruuk: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PacifistHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PacifistChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/Pacifist/PacifistFistAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PacifistSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/PacifistBlueprint"
|
|
||||||
],
|
|
||||||
Hildryn: [
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/IronframeHelmetBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/IronframeChassisBlueprint",
|
|
||||||
"/Lotus/StoreItems/Powersuits/IronFrame/IronFrameStripAugmentCard",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/IronframeSystemsBlueprint",
|
|
||||||
"/Lotus/StoreItems/Types/Recipes/WarframeRecipes/IronframeBlueprint"
|
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateNormalModeRewards = (choices: string[]): IEndlessXpReward[] => {
|
|
||||||
const choiceRewards = normalModeChosenRewards[choices[0]];
|
|
||||||
return [
|
|
||||||
{
|
{
|
||||||
RequiredTotalXp: 190,
|
RequiredTotalXp: 190,
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessNormalSilverRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 400,
|
|
||||||
Rewards: [
|
Rewards: [
|
||||||
{
|
{
|
||||||
StoreItem: choiceRewards[0],
|
StoreItem: "/Lotus/StoreItems/Upgrades/Mods/Aura/PlayerHealthAuraMod",
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 630,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessNormalSilverRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 890,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessNormalMODRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 1190,
|
|
||||||
Rewards: [
|
|
||||||
{
|
|
||||||
StoreItem: choiceRewards[1],
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 1540,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessNormalGoldRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 1950,
|
|
||||||
Rewards: [
|
|
||||||
{
|
|
||||||
StoreItem: choiceRewards[2],
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 2430,
|
|
||||||
Rewards: [
|
|
||||||
{
|
|
||||||
StoreItem: choiceRewards[3],
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 2990,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessNormalArcaneRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 3640,
|
|
||||||
Rewards: [
|
|
||||||
{
|
|
||||||
StoreItem: choiceRewards[4],
|
|
||||||
ItemCount: 1
|
ItemCount: 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
];
|
// ...
|
||||||
|
]
|
||||||
|
}
|
||||||
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
const hardModeChosenRewards: Record<string, string> = {
|
interface IEndlessXpRequest {
|
||||||
Braton: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/BratonIncarnonUnlocker",
|
Mode: string; // "r"
|
||||||
Lato: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/LatoIncarnonUnlocker",
|
Category: TEndlessXpCategory;
|
||||||
Skana: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/SkanaIncarnonUnlocker",
|
Choices: string[];
|
||||||
Paris: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/ParisIncarnonUnlocker",
|
}
|
||||||
Kunai: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/KunaiIncarnonUnlocker",
|
|
||||||
Boar: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/BoarIncarnonUnlocker",
|
|
||||||
Gammacor: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/GammacorIncarnonUnlocker",
|
|
||||||
Anku: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/AnkuIncarnonUnlocker",
|
|
||||||
Gorgon: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/GorgonIncarnonUnlocker",
|
|
||||||
Angstrum: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/AngstrumIncarnonUnlocker",
|
|
||||||
Bo: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/BoIncarnonUnlocker",
|
|
||||||
Latron: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/LatronIncarnonUnlocker",
|
|
||||||
Furis: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/FurisIncarnonUnlocker",
|
|
||||||
Furax: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/FuraxIncarnonUnlocker",
|
|
||||||
Strun: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/StrunIncarnonUnlocker",
|
|
||||||
Lex: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/LexIncarnonUnlocker",
|
|
||||||
Magistar: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/MagistarIncarnonUnlocker",
|
|
||||||
Boltor: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/BoltorIncarnonUnlocker",
|
|
||||||
Bronco: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/BroncoIncarnonUnlocker",
|
|
||||||
CeramicDagger: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/CeramicDaggerIncarnonUnlocker",
|
|
||||||
Torid: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/ToridIncarnonUnlocker",
|
|
||||||
DualToxocyst: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/DualToxocystIncarnonUnlocker",
|
|
||||||
DualIchor: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/DualIchorIncarnonUnlocker",
|
|
||||||
Miter: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/MiterIncarnonUnlocker",
|
|
||||||
Atomos: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/AtomosIncarnonUnlocker",
|
|
||||||
AckAndBrunt: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/AckAndBruntIncarnonUnlocker",
|
|
||||||
Soma: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/SomaIncarnonUnlocker",
|
|
||||||
Vasto: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/VastoIncarnonUnlocker",
|
|
||||||
NamiSolo: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/NamiSoloIncarnonUnlocker",
|
|
||||||
Burston: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/BurstonIncarnonUnlocker",
|
|
||||||
Zylok: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/ZylokIncarnonUnlocker",
|
|
||||||
Sibear: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/SibearIncarnonUnlocker",
|
|
||||||
Dread: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/DreadIncarnonUnlocker",
|
|
||||||
Despair: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/DespairIncarnonUnlocker",
|
|
||||||
Hate: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/HateIncarnonUnlocker",
|
|
||||||
Dera: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/DeraIncarnonUnlocker",
|
|
||||||
Cestra: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/CestraIncarnonUnlocker",
|
|
||||||
Okina: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Melee/OkinaIncarnonUnlocker",
|
|
||||||
Sybaris: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Primary/SybarisIncarnonUnlocker",
|
|
||||||
Sicarus: "/Lotus/StoreItems/Types/Items/MiscItems/IncarnonAdapters/Secondary/SicarusIncarnonUnlocker",
|
|
||||||
RivenPrimary: "/Lotus/StoreItems/Upgrades/Mods/Randomized/RawRifleRandomMod",
|
|
||||||
RivenSecondary: "/Lotus/StoreItems/Upgrades/Mods/Randomized/RawPistolRandomMod",
|
|
||||||
RivenMelee: "/Lotus/StoreItems/Upgrades/Mods/Randomized/RawMeleeRandomMod",
|
|
||||||
Kuva: "/Lotus/Types/Game/DuviriEndless/CircuitSteelPathBIGKuvaReward"
|
|
||||||
};
|
|
||||||
|
|
||||||
const generateHardModeRewards = (choices: string[]): IEndlessXpReward[] => {
|
|
||||||
return [
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 285,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathSilverRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 600,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathArcaneRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 945,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathSilverRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 1335,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathSilverRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 1785,
|
|
||||||
Rewards: [
|
|
||||||
{
|
|
||||||
StoreItem: hardModeChosenRewards[choices[0]],
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 2310,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathGoldRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 2925,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathGoldRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 3645,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathArcaneRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 4485,
|
|
||||||
Rewards: generateRandomRewards(
|
|
||||||
"/Lotus/Types/Game/MissionDecks/DuviriEndlessCircuitRewards/DuviriEndlessSteelPathSteelEssenceRewards"
|
|
||||||
)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
RequiredTotalXp: 5460,
|
|
||||||
Rewards: [
|
|
||||||
{
|
|
||||||
StoreItem: hardModeChosenRewards[choices[1]],
|
|
||||||
ItemCount: 1
|
|
||||||
}
|
|
||||||
]
|
|
||||||
}
|
|
||||||
];
|
|
||||||
};
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { toMongoDate } from "../../helpers/inventoryHelpers.ts";
|
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getInventory, updateEntratiVault } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const entratiLabConquestModeController: RequestHandler = async (req, res) => {
|
export const entratiLabConquestModeController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -11,7 +11,24 @@ export const entratiLabConquestModeController: RequestHandler = async (req, res)
|
|||||||
"EntratiVaultCountResetDate EntratiVaultCountLastPeriod EntratiLabConquestUnlocked EchoesHexConquestUnlocked EchoesHexConquestActiveFrameVariants EchoesHexConquestActiveStickers EntratiLabConquestActiveFrameVariants EntratiLabConquestCacheScoreMission EchoesHexConquestCacheScoreMission"
|
"EntratiVaultCountResetDate EntratiVaultCountLastPeriod EntratiLabConquestUnlocked EchoesHexConquestUnlocked EchoesHexConquestActiveFrameVariants EchoesHexConquestActiveStickers EntratiLabConquestActiveFrameVariants EntratiLabConquestCacheScoreMission EchoesHexConquestCacheScoreMission"
|
||||||
);
|
);
|
||||||
const body = getJSONfromString<IEntratiLabConquestModeRequest>(String(req.body));
|
const body = getJSONfromString<IEntratiLabConquestModeRequest>(String(req.body));
|
||||||
updateEntratiVault(inventory);
|
if (!inventory.EntratiVaultCountResetDate || Date.now() >= inventory.EntratiVaultCountResetDate.getTime()) {
|
||||||
|
const EPOCH = 1734307200 * 1000; // Mondays, amirite?
|
||||||
|
const day = Math.trunc((Date.now() - EPOCH) / 86400000);
|
||||||
|
const week = Math.trunc(day / 7);
|
||||||
|
const weekStart = EPOCH + week * 604800000;
|
||||||
|
const weekEnd = weekStart + 604800000;
|
||||||
|
inventory.EntratiVaultCountLastPeriod = 0;
|
||||||
|
inventory.EntratiVaultCountResetDate = new Date(weekEnd);
|
||||||
|
if (inventory.EntratiLabConquestUnlocked) {
|
||||||
|
inventory.EntratiLabConquestUnlocked = 0;
|
||||||
|
inventory.EntratiLabConquestActiveFrameVariants = [];
|
||||||
|
}
|
||||||
|
if (inventory.EchoesHexConquestUnlocked) {
|
||||||
|
inventory.EchoesHexConquestUnlocked = 0;
|
||||||
|
inventory.EchoesHexConquestActiveFrameVariants = [];
|
||||||
|
inventory.EchoesHexConquestActiveStickers = [];
|
||||||
|
}
|
||||||
|
}
|
||||||
if (body.BuyMode) {
|
if (body.BuyMode) {
|
||||||
inventory.EntratiVaultCountLastPeriod! += 2;
|
inventory.EntratiVaultCountLastPeriod! += 2;
|
||||||
if (body.IsEchoesDeepArchemedea) {
|
if (body.IsEchoesDeepArchemedea) {
|
||||||
@ -32,7 +49,7 @@ export const entratiLabConquestModeController: RequestHandler = async (req, res)
|
|||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
EntratiVaultCountResetDate: toMongoDate(inventory.EntratiVaultCountResetDate!),
|
EntratiVaultCountResetDate: toMongoDate(inventory.EntratiVaultCountResetDate),
|
||||||
EntratiVaultCountLastPeriod: inventory.EntratiVaultCountLastPeriod,
|
EntratiVaultCountLastPeriod: inventory.EntratiVaultCountLastPeriod,
|
||||||
EntratiLabConquestUnlocked: inventory.EntratiLabConquestUnlocked,
|
EntratiLabConquestUnlocked: inventory.EntratiLabConquestUnlocked,
|
||||||
EntratiLabConquestCacheScoreMission: inventory.EntratiLabConquestCacheScoreMission,
|
EntratiLabConquestCacheScoreMission: inventory.EntratiLabConquestCacheScoreMission,
|
||||||
|
|||||||
@ -1,10 +1,9 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addMiscItems, getInventory } from "../../services/inventoryService.ts";
|
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import type { WeaponTypeInternal } from "../../services/itemDataService.ts";
|
import { getRecipe, WeaponTypeInternal } from "@/src/services/itemDataService";
|
||||||
import { getRecipe } from "../../services/itemDataService.ts";
|
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { EquipmentFeatures } from "../../types/equipmentTypes.ts";
|
|
||||||
|
|
||||||
export const evolveWeaponController: RequestHandler = async (req, res) => {
|
export const evolveWeaponController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getSession } from "../../managers/sessionManager.ts";
|
import { getSession } from "@/src/managers/sessionManager";
|
||||||
import { logger } from "../../utils/logger.ts";
|
import { logger } from "@/src/utils/logger";
|
||||||
import type { IFindSessionRequest } from "../../types/session.ts";
|
import { IFindSessionRequest } from "@/src/types/session";
|
||||||
|
|
||||||
export const findSessionsController: RequestHandler = (_req, res) => {
|
export const findSessionsController: RequestHandler = (_req, res) => {
|
||||||
const req = JSON.parse(String(_req.body)) as IFindSessionRequest;
|
const req = JSON.parse(String(_req.body)) as IFindSessionRequest;
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { addMiscItems, addStanding, getInventory } from "../../services/inventoryService.ts";
|
import { addMiscItems, addStanding, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ExportResources } from "warframe-public-export-plus";
|
import { ExportResources } from "warframe-public-export-plus";
|
||||||
|
|
||||||
export const fishmongerController: RequestHandler = async (req, res) => {
|
export const fishmongerController: RequestHandler = async (req, res) => {
|
||||||
@ -30,14 +30,15 @@ export const fishmongerController: RequestHandler = async (req, res) => {
|
|||||||
miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 });
|
miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 });
|
||||||
}
|
}
|
||||||
addMiscItems(inventory, miscItemChanges);
|
addMiscItems(inventory, miscItemChanges);
|
||||||
if (gainedStanding && syndicateTag) addStanding(inventory, syndicateTag, gainedStanding);
|
let affiliationMod;
|
||||||
|
if (gainedStanding && syndicateTag) affiliationMod = addStanding(inventory, syndicateTag, gainedStanding);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: {
|
InventoryChanges: {
|
||||||
MiscItems: miscItemChanges
|
MiscItems: miscItemChanges
|
||||||
},
|
},
|
||||||
SyndicateTag: syndicateTag,
|
SyndicateTag: syndicateTag,
|
||||||
StandingChange: gainedStanding
|
StandingChange: affiliationMod?.Standing || 0
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,11 +1,11 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getInventory, addMiscItems, addEquipment, occupySlot } from "../../services/inventoryService.ts";
|
import { getInventory, addMiscItems, addEquipment, occupySlot } from "@/src/services/inventoryService";
|
||||||
import type { IMiscItem, TFocusPolarity, TEquipmentKey } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { IMiscItem, TFocusPolarity, TEquipmentKey, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { InventorySlot } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { logger } from "../../utils/logger.ts";
|
|
||||||
import { ExportFocusUpgrades } from "warframe-public-export-plus";
|
import { ExportFocusUpgrades } from "warframe-public-export-plus";
|
||||||
import { Inventory } from "../../models/inventoryModels/inventoryModel.ts";
|
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
|
|
||||||
export const focusController: RequestHandler = async (req, res) => {
|
export const focusController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -38,12 +38,12 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
case FocusOperation.UnlockWay: {
|
case FocusOperation.UnlockWay: {
|
||||||
const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
|
const focusType = (JSON.parse(String(req.body)) as IWayRequest).FocusType;
|
||||||
const focusPolarity = focusTypeToPolarity(focusType);
|
const focusPolarity = focusTypeToPolarity(focusType);
|
||||||
const inventory = await getInventory(accountId, "FocusAbility FocusUpgrades FocusXP");
|
const inventory = await getInventory(accountId);
|
||||||
const cost = inventory.FocusAbility ? 50_000 : 0;
|
const cost = inventory.FocusAbility ? 50_000 : 0;
|
||||||
inventory.FocusAbility ??= focusType;
|
inventory.FocusAbility ??= focusType;
|
||||||
inventory.FocusUpgrades.push({ ItemType: focusType });
|
inventory.FocusUpgrades.push({ ItemType: focusType });
|
||||||
if (cost) {
|
if (inventory.FocusXP) {
|
||||||
inventory.FocusXP![focusPolarity]! -= cost;
|
inventory.FocusXP[focusPolarity] -= cost;
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
@ -64,9 +64,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
|
||||||
res.json({
|
res.end();
|
||||||
FocusUpgrade: { ItemType: focusType }
|
|
||||||
});
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FocusOperation.UnlockUpgrade: {
|
case FocusOperation.UnlockUpgrade: {
|
||||||
@ -78,7 +76,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
|
cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
|
||||||
inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
|
inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
|
||||||
}
|
}
|
||||||
inventory.FocusXP![focusPolarity]! -= cost;
|
inventory.FocusXP![focusPolarity] -= cost;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
FocusTypes: request.FocusTypes,
|
FocusTypes: request.FocusTypes,
|
||||||
@ -96,7 +94,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
|
const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
|
||||||
focusUpgradeDb.Level = focusUpgrade.Level;
|
focusUpgradeDb.Level = focusUpgrade.Level;
|
||||||
}
|
}
|
||||||
inventory.FocusXP![focusPolarity]! -= cost;
|
inventory.FocusXP![focusPolarity] -= cost;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
FocusInfos: request.FocusInfos,
|
FocusInfos: request.FocusInfos,
|
||||||
@ -106,24 +104,23 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
case FocusOperation.SentTrainingAmplifier: {
|
case FocusOperation.SentTrainingAmplifier: {
|
||||||
const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
|
const request = JSON.parse(String(req.body)) as ISentTrainingAmplifierRequest;
|
||||||
const inventory = await getInventory(accountId);
|
const parts: string[] = [
|
||||||
const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, {
|
|
||||||
ModularParts: [
|
|
||||||
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingGrip",
|
||||||
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingChassis",
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingChassis",
|
||||||
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingBarrel"
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/SentTrainingAmplifier/SentAmpTrainingBarrel"
|
||||||
]
|
];
|
||||||
});
|
const inventory = await getInventory(accountId);
|
||||||
|
const inventoryChanges = addEquipment(inventory, "OperatorAmps", request.StartingWeaponType, parts);
|
||||||
occupySlot(inventory, InventorySlot.AMPS, false);
|
occupySlot(inventory, InventorySlot.AMPS, false);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json(inventoryChanges.OperatorAmps![0]);
|
res.json((inventoryChanges.OperatorAmps as IEquipmentClient[])[0]);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case FocusOperation.UnbindUpgrade: {
|
case FocusOperation.UnbindUpgrade: {
|
||||||
const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
|
const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
|
||||||
const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
|
const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
inventory.FocusXP![focusPolarity]! -= 750_000 * request.FocusTypes.length;
|
inventory.FocusXP![focusPolarity] -= 750_000 * request.FocusTypes.length;
|
||||||
addMiscItems(inventory, [
|
addMiscItems(inventory, [
|
||||||
{
|
{
|
||||||
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem",
|
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem",
|
||||||
@ -168,10 +165,8 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
shard.ItemCount *= -1;
|
shard.ItemCount *= -1;
|
||||||
}
|
}
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const polarity = request.Polarity;
|
inventory.FocusXP ??= { AP_POWER: 0, AP_TACTIC: 0, AP_DEFENSE: 0, AP_ATTACK: 0, AP_WARD: 0 };
|
||||||
inventory.FocusXP ??= {};
|
inventory.FocusXP[request.Polarity] += xp;
|
||||||
inventory.FocusXP[polarity] ??= 0;
|
|
||||||
inventory.FocusXP[polarity] += xp;
|
|
||||||
addMiscItems(inventory, request.Shards);
|
addMiscItems(inventory, request.Shards);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
break;
|
break;
|
||||||
@ -231,7 +226,7 @@ interface ILensInstallRequest {
|
|||||||
|
|
||||||
// Works for ways & upgrades
|
// Works for ways & upgrades
|
||||||
const focusTypeToPolarity = (type: string): TFocusPolarity => {
|
const focusTypeToPolarity = (type: string): TFocusPolarity => {
|
||||||
return ("AP_" + type.substring(1).split("/")[3].toUpperCase()) as TFocusPolarity;
|
return ("AP_" + type.substr(1).split("/")[3].toUpperCase()) as TFocusPolarity;
|
||||||
};
|
};
|
||||||
|
|
||||||
const shardValues = {
|
const shardValues = {
|
||||||
|
|||||||
@ -1,15 +1,23 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { ExportResources } from "warframe-public-export-plus";
|
import { ExportResources } from "warframe-public-export-plus";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { addFusionTreasures, addMiscItems, getInventory } from "../../services/inventoryService.ts";
|
import { addFusionTreasures, addMiscItems, getInventory } from "@/src/services/inventoryService";
|
||||||
import type { IMiscItem } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { IFusionTreasure, IMiscItem } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { parseFusionTreasure } from "../../helpers/inventoryHelpers.ts";
|
|
||||||
|
|
||||||
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);
|
||||||
|
|||||||
@ -1,83 +0,0 @@
|
|||||||
import { toMongoDate } from "../../helpers/inventoryHelpers.ts";
|
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
|
||||||
import { addMiscItem, getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { toStoreItem } from "../../services/itemDataService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import { createGarden, getPersonalRooms } from "../../services/personalRoomsService.ts";
|
|
||||||
import type { IMongoDate } from "../../types/commonTypes.ts";
|
|
||||||
import type { IMissionReward } from "../../types/missionTypes.ts";
|
|
||||||
import type { IGardeningClient, IPersonalRoomsClient } from "../../types/personalRoomsTypes.ts";
|
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
import { dict_en, ExportResources } from "warframe-public-export-plus";
|
|
||||||
|
|
||||||
export const gardeningController: RequestHandler = async (req, res) => {
|
|
||||||
const data = getJSONfromString<IGardeningRequest>(String(req.body));
|
|
||||||
if (data.Mode != "HarvestAll") {
|
|
||||||
throw new Error(`unexpected gardening mode: ${data.Mode}`);
|
|
||||||
}
|
|
||||||
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const [inventory, personalRooms] = await Promise.all([
|
|
||||||
getInventory(accountId, "MiscItems"),
|
|
||||||
getPersonalRooms(accountId, "Apartment")
|
|
||||||
]);
|
|
||||||
|
|
||||||
// Harvest plants
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
|
||||||
const rewards: Record<string, IMissionReward[][]> = {};
|
|
||||||
for (const planter of personalRooms.Apartment.Gardening.Planters) {
|
|
||||||
rewards[planter.Name] = [];
|
|
||||||
for (const plant of planter.Plants) {
|
|
||||||
const itemType =
|
|
||||||
"/Lotus/Types/Gameplay/Duviri/Resource/DuviriPlantItem" +
|
|
||||||
plant.PlantType.substring(plant.PlantType.length - 1);
|
|
||||||
const itemCount = Math.random() < 0.775 ? 2 : 4;
|
|
||||||
|
|
||||||
addMiscItem(inventory, itemType, itemCount, inventoryChanges);
|
|
||||||
|
|
||||||
rewards[planter.Name].push([
|
|
||||||
{
|
|
||||||
StoreItem: toStoreItem(itemType),
|
|
||||||
TypeName: itemType,
|
|
||||||
ItemCount: itemCount,
|
|
||||||
DailyCooldown: false,
|
|
||||||
Rarity: itemCount == 2 ? 0.7743589743589744 : 0.22564102564102564,
|
|
||||||
TweetText: `${itemCount}x ${dict_en[ExportResources[itemType].name]} (Resource)`,
|
|
||||||
ProductCategory: "MiscItems"
|
|
||||||
}
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Refresh garden
|
|
||||||
personalRooms.Apartment.Gardening = createGarden();
|
|
||||||
|
|
||||||
await Promise.all([inventory.save(), personalRooms.save()]);
|
|
||||||
|
|
||||||
const planter = personalRooms.Apartment.Gardening.Planters[personalRooms.Apartment.Gardening.Planters.length - 1];
|
|
||||||
const plant = planter.Plants[planter.Plants.length - 1];
|
|
||||||
res.json({
|
|
||||||
GardenTagName: planter.Name,
|
|
||||||
PlantType: plant.PlantType,
|
|
||||||
PlotIndex: plant.PlotIndex,
|
|
||||||
EndTime: toMongoDate(plant.EndTime),
|
|
||||||
InventoryChanges: inventoryChanges,
|
|
||||||
Gardening: personalRooms.toJSON<IPersonalRoomsClient>().Apartment.Gardening,
|
|
||||||
Rewards: rewards
|
|
||||||
} satisfies IGardeningResponse);
|
|
||||||
};
|
|
||||||
|
|
||||||
interface IGardeningRequest {
|
|
||||||
Mode: string;
|
|
||||||
}
|
|
||||||
|
|
||||||
interface IGardeningResponse {
|
|
||||||
GardenTagName: string;
|
|
||||||
PlantType: string;
|
|
||||||
PlotIndex: number;
|
|
||||||
EndTime: IMongoDate;
|
|
||||||
InventoryChanges: IInventoryChanges;
|
|
||||||
Gardening: IGardeningClient;
|
|
||||||
Rewards: Record<string, IMissionReward[][]>;
|
|
||||||
}
|
|
||||||
@ -1,8 +1,8 @@
|
|||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { updateGeneric } from "../../services/inventoryService.ts";
|
import { updateGeneric } from "@/src/services/inventoryService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import type { IGenericUpdate } from "../../types/genericUpdate.ts";
|
import { IGenericUpdate } from "@/src/types/genericUpdate";
|
||||||
|
|
||||||
// This endpoint used to be /api/genericUpdate.php, but sometime around the Jade Shadows update, it was changed to /api/updateNodeIntros.php.
|
// This endpoint used to be /api/genericUpdate.php, but sometime around the Jade Shadows update, it was changed to /api/updateNodeIntros.php.
|
||||||
// SpaceNinjaServer supports both endpoints right now.
|
// SpaceNinjaServer supports both endpoints right now.
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { Alliance, Guild } from "../../models/guildModel.ts";
|
import { Alliance, Guild } from "@/src/models/guildModel";
|
||||||
import { getAllianceClient } from "../../services/guildService.ts";
|
import { getAllianceClient } from "@/src/services/guildService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getAllianceController: RequestHandler = async (req, res) => {
|
export const getAllianceController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -18,7 +18,6 @@ export const getAllianceController: RequestHandler = async (req, res) => {
|
|||||||
res.end();
|
res.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
// POST request since U27
|
|
||||||
/*interface IGetAllianceRequest {
|
/*interface IGetAllianceRequest {
|
||||||
memberCount: number;
|
memberCount: number;
|
||||||
clanLeaderName: string;
|
clanLeaderName: string;
|
||||||
|
|||||||
@ -1,10 +1,8 @@
|
|||||||
import { DailyDeal } from "../../models/worldStateModel.ts";
|
import { RequestHandler } from "express";
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const getDailyDealStockLevelsController: RequestHandler = async (req, res) => {
|
export const getDailyDealStockLevelsController: RequestHandler = (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: dailyDeal.AmountSold
|
AmountSold: 0
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,54 +1,15 @@
|
|||||||
import { toOid } from "../../helpers/inventoryHelpers.ts";
|
import { Request, Response } from "express";
|
||||||
import { Friendship } from "../../models/friendModel.ts";
|
|
||||||
import { addAccountDataToFriendInfo, addInventoryDataToFriendInfo } from "../../services/friendService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import type { IFriendInfo } from "../../types/friendTypes.ts";
|
|
||||||
import type { Request, RequestHandler, Response } from "express";
|
|
||||||
|
|
||||||
// POST with {} instead of GET as of 38.5.0
|
// POST with {} instead of GET as of 38.5.0
|
||||||
export const getFriendsController: RequestHandler = async (req: Request, res: Response) => {
|
const getFriendsController = (_request: Request, response: Response): void => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
response.writeHead(200, {
|
||||||
const response: IGetFriendsResponse = {
|
//Connection: "keep-alive",
|
||||||
Current: [],
|
//"Content-Encoding": "gzip",
|
||||||
IncomingFriendRequests: [],
|
"Content-Type": "text/html",
|
||||||
OutgoingFriendRequests: []
|
// charset: "UTF - 8",
|
||||||
};
|
"Content-Length": "3"
|
||||||
const [internalFriendships, externalFriendships] = await Promise.all([
|
|
||||||
Friendship.find({ owner: accountId }),
|
|
||||||
Friendship.find({ friend: accountId }, "owner Note")
|
|
||||||
]);
|
|
||||||
for (const externalFriendship of externalFriendships) {
|
|
||||||
if (!internalFriendships.find(x => x.friend.equals(externalFriendship.owner))) {
|
|
||||||
response.IncomingFriendRequests.push({
|
|
||||||
_id: toOid(externalFriendship.owner),
|
|
||||||
Note: externalFriendship.Note
|
|
||||||
});
|
});
|
||||||
}
|
response.end(Buffer.from([0x7b, 0x7d, 0x0a]));
|
||||||
}
|
|
||||||
for (const internalFriendship of internalFriendships) {
|
|
||||||
const friendInfo: IFriendInfo = {
|
|
||||||
_id: toOid(internalFriendship.friend)
|
|
||||||
};
|
|
||||||
if (externalFriendships.find(x => x.owner.equals(internalFriendship.friend))) {
|
|
||||||
response.Current.push(friendInfo);
|
|
||||||
} else {
|
|
||||||
response.OutgoingFriendRequests.push(friendInfo);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
const promises: Promise<void>[] = [];
|
|
||||||
for (const arr of Object.values(response)) {
|
|
||||||
for (const friendInfo of arr) {
|
|
||||||
promises.push(addAccountDataToFriendInfo(friendInfo));
|
|
||||||
promises.push(addInventoryDataToFriendInfo(friendInfo));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await Promise.all(promises);
|
|
||||||
res.json(response);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// interface IGetFriendsResponse {
|
export { getFriendsController };
|
||||||
// Current: IFriendInfo[];
|
|
||||||
// IncomingFriendRequests: IFriendInfo[];
|
|
||||||
// OutgoingFriendRequests: IFriendInfo[];
|
|
||||||
// }
|
|
||||||
type IGetFriendsResponse = Record<"Current" | "IncomingFriendRequests" | "OutgoingFriendRequests", IFriendInfo[]>;
|
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { GuildMember } from "../../models/guildModel.ts";
|
import { GuildMember } from "@/src/models/guildModel";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { IGuildMemberClient } from "../../types/guildTypes.ts";
|
import { IGuildMemberClient } from "@/src/types/guildTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getGuildContributionsController: RequestHandler = async (req, res) => {
|
export const getGuildContributionsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,13 +1,13 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Guild } from "../../models/guildModel.ts";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { logger } from "../../utils/logger.ts";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { createUniqueClanName, getGuildClient } from "../../services/guildService.ts";
|
import { createUniqueClanName, getGuildClient } from "@/src/services/guildService";
|
||||||
|
|
||||||
export const getGuildController: RequestHandler = async (req, res) => {
|
export const getGuildController: RequestHandler = async (req, res) => {
|
||||||
const account = await getAccountForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(account._id.toString(), "GuildId");
|
const inventory = await getInventory(accountId, "GuildId");
|
||||||
if (inventory.GuildId) {
|
if (inventory.GuildId) {
|
||||||
const guild = await Guild.findById(inventory.GuildId);
|
const guild = await Guild.findById(inventory.GuildId);
|
||||||
if (guild) {
|
if (guild) {
|
||||||
@ -24,7 +24,7 @@ export const getGuildController: RequestHandler = async (req, res) => {
|
|||||||
guild.CeremonyResetDate = undefined;
|
guild.CeremonyResetDate = undefined;
|
||||||
await guild.save();
|
await guild.save();
|
||||||
}
|
}
|
||||||
res.json(await getGuildClient(guild, account));
|
res.json(await getGuildClient(guild, accountId));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,8 +1,7 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { Guild } from "../../models/guildModel.ts";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
import { getDojoClient } from "../../services/guildService.ts";
|
import { getDojoClient } from "@/src/services/guildService";
|
||||||
import { Account } from "../../models/loginModel.ts";
|
|
||||||
|
|
||||||
export const getGuildDojoController: RequestHandler = async (req, res) => {
|
export const getGuildDojoController: RequestHandler = async (req, res) => {
|
||||||
const guildId = req.query.guildId as string;
|
const guildId = req.query.guildId as string;
|
||||||
@ -26,8 +25,7 @@ export const getGuildDojoController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
const payload: IGetGuildDojoRequest = req.body ? (JSON.parse(String(req.body)) as IGetGuildDojoRequest) : {};
|
const payload: IGetGuildDojoRequest = req.body ? (JSON.parse(String(req.body)) as IGetGuildDojoRequest) : {};
|
||||||
const account = await Account.findById(req.query.accountId as string);
|
res.json(await getDojoClient(guild, 0, payload.ComponentId));
|
||||||
res.json(await getDojoClient(guild, 0, payload.ComponentId, account?.BuildLabel));
|
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IGetGuildDojoRequest {
|
interface IGetGuildDojoRequest {
|
||||||
|
|||||||
@ -1,26 +0,0 @@
|
|||||||
import type { RequestHandler } from "express";
|
|
||||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { Guild } from "../../models/guildModel.ts";
|
|
||||||
|
|
||||||
export const getGuildEventScoreController: RequestHandler = async (req, res) => {
|
|
||||||
const account = await getAccountForRequest(req);
|
|
||||||
const inventory = await getInventory(account._id.toString(), "GuildId");
|
|
||||||
const guild = await Guild.findById(inventory.GuildId);
|
|
||||||
const goalId = req.query.goalId as string;
|
|
||||||
if (guild && guild.GoalProgress && goalId) {
|
|
||||||
const goal = guild.GoalProgress.find(x => x.goalId.toString() == goalId);
|
|
||||||
if (goal) {
|
|
||||||
res.json({
|
|
||||||
Tier: guild.Tier,
|
|
||||||
GoalProgress: {
|
|
||||||
Count: goal.Count,
|
|
||||||
Tag: goal.Tag,
|
|
||||||
_id: { $oid: goal.goalId }
|
|
||||||
}
|
|
||||||
});
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
res.json({});
|
|
||||||
};
|
|
||||||
@ -1,9 +1,9 @@
|
|||||||
import { toMongoDate } from "../../helpers/inventoryHelpers.ts";
|
import { toMongoDate } from "@/src/helpers/inventoryHelpers";
|
||||||
import { Guild } from "../../models/guildModel.ts";
|
import { Guild } from "@/src/models/guildModel";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { IMongoDate } from "../../types/commonTypes.ts";
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getGuildLogController: RequestHandler = async (req, res) => {
|
export const getGuildLogController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { toOid } from "../../helpers/inventoryHelpers.ts";
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { Account, Ignore } from "../../models/loginModel.ts";
|
import { Account, Ignore } from "@/src/models/loginModel";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { IFriendInfo } from "../../types/friendTypes.ts";
|
import { IFriendInfo } from "@/src/types/guildTypes";
|
||||||
import { parallelForeach } from "../../utils/async-utils.ts";
|
import { parallelForeach } from "@/src/utils/async-utils";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getIgnoredUsersController: RequestHandler = async (req, res) => {
|
export const getIgnoredUsersController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,7 +1,7 @@
|
|||||||
import { Inventory } from "../../models/inventoryModels/inventoryModel.ts";
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { generateRewardSeed } from "@/src/services/inventoryService";
|
||||||
import { generateRewardSeed } from "../../services/rngService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getNewRewardSeedController: RequestHandler = async (req, res) => {
|
export const getNewRewardSeedController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,62 +0,0 @@
|
|||||||
import type { RequestHandler } from "express";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { EPOCH, getSeasonChallengePools, getWorldState, pushWeeklyActs } from "../../services/worldStateService.ts";
|
|
||||||
import { unixTimesInMs } from "../../constants/timeConstants.ts";
|
|
||||||
import type { ISeasonChallenge } from "../../types/worldStateTypes.ts";
|
|
||||||
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 });
|
|
||||||
}
|
|
||||||
};
|
|
||||||
@ -1,33 +1,43 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { config } from "@/src/services/configService";
|
||||||
import { createGarden, getPersonalRooms } from "../../services/personalRoomsService.ts";
|
import allShipFeatures from "@/static/fixed_responses/allShipFeatures.json";
|
||||||
import type { IGetShipResponse, IPersonalRoomsClient } from "../../types/personalRoomsTypes.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { getLoadout } from "../../services/loadoutService.ts";
|
import { getPersonalRooms } from "@/src/services/personalRoomsService";
|
||||||
import { toOid } from "../../helpers/inventoryHelpers.ts";
|
import { getShip } from "@/src/services/shipService";
|
||||||
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
|
import { IGetShipResponse } from "@/src/types/shipTypes";
|
||||||
|
import { IPersonalRooms } from "@/src/types/personalRoomsTypes";
|
||||||
|
import { getLoadout } from "@/src/services/loadoutService";
|
||||||
|
|
||||||
export const getShipController: RequestHandler = async (req, res) => {
|
export const getShipController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const personalRoomsDb = await getPersonalRooms(accountId);
|
const personalRoomsDb = await getPersonalRooms(accountId);
|
||||||
|
const personalRooms = personalRoomsDb.toJSON<IPersonalRooms>();
|
||||||
// Setup gardening if it's missing. Maybe should be done as part of some quest completion in the future.
|
|
||||||
if (personalRoomsDb.Apartment.Gardening.Planters.length == 0) {
|
|
||||||
personalRoomsDb.Apartment.Gardening = createGarden();
|
|
||||||
await personalRoomsDb.save();
|
|
||||||
}
|
|
||||||
|
|
||||||
const personalRooms = personalRoomsDb.toJSON<IPersonalRoomsClient>();
|
|
||||||
const loadout = await getLoadout(accountId);
|
const loadout = await getLoadout(accountId);
|
||||||
|
const ship = await getShip(personalRoomsDb.activeShipId, "ShipAttachments SkinFlavourItem");
|
||||||
|
|
||||||
const getShipResponse: IGetShipResponse = {
|
const getShipResponse: IGetShipResponse = {
|
||||||
ShipOwnerId: accountId,
|
ShipOwnerId: accountId,
|
||||||
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: ship.ShipAttachments,
|
||||||
|
SkinFlavourItem: ship.SkinFlavourItem
|
||||||
|
},
|
||||||
|
FavouriteLoadoutId: personalRooms.Ship.FavouriteLoadoutId
|
||||||
|
? toOid(personalRooms.Ship.FavouriteLoadoutId)
|
||||||
|
: undefined
|
||||||
},
|
},
|
||||||
Apartment: personalRooms.Apartment,
|
Apartment: personalRooms.Apartment,
|
||||||
TailorShop: personalRooms.TailorShop
|
TailorShop: personalRooms.TailorShop
|
||||||
};
|
};
|
||||||
|
|
||||||
|
if (config.unlockAllShipFeatures) {
|
||||||
|
getShipResponse.Ship.Features = allShipFeatures;
|
||||||
|
}
|
||||||
|
|
||||||
res.json(getShipResponse);
|
res.json(getShipResponse);
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,29 +1,14 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { applyStandingToVendorManifest, getVendorManifestByTypeName } from "../../services/serversideVendorsService.ts";
|
import { getVendorManifestByTypeName } from "@/src/services/serversideVendorsService";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
|
||||||
import { config } from "../../services/configService.ts";
|
|
||||||
|
|
||||||
export const getVendorInfoController: RequestHandler = async (req, res) => {
|
export const getVendorInfoController: RequestHandler = (req, res) => {
|
||||||
let manifest = getVendorManifestByTypeName(req.query.vendor as string);
|
if (typeof req.query.vendor == "string") {
|
||||||
|
const manifest = getVendorManifestByTypeName(req.query.vendor);
|
||||||
if (!manifest) {
|
if (!manifest) {
|
||||||
throw new Error(`Unknown vendor: ${req.query.vendor as string}`);
|
throw new Error(`Unknown vendor: ${req.query.vendor}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// For testing purposes, authenticating with this endpoint is optional here, but would be required on live.
|
|
||||||
if (req.query.accountId) {
|
|
||||||
const accountId = await getAccountIdForRequest(req);
|
|
||||||
const inventory = await getInventory(accountId);
|
|
||||||
manifest = applyStandingToVendorManifest(inventory, manifest);
|
|
||||||
if (config.dev?.keepVendorsExpired) {
|
|
||||||
manifest = {
|
|
||||||
VendorInfo: {
|
|
||||||
...manifest.VendorInfo,
|
|
||||||
Expiry: { $date: { $numberLong: "0" } }
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
res.json(manifest);
|
res.json(manifest);
|
||||||
|
} else {
|
||||||
|
res.status(400).end();
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,9 +1,9 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { crackRelic } from "../../helpers/relicHelper.ts";
|
import { crackRelic } from "@/src/helpers/relicHelper";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { IVoidTearParticipantInfo } from "../../types/requestTypes.ts";
|
import { IVoidTearParticipantInfo } from "@/src/types/requestTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
|
export const getVoidProjectionRewardsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,35 +1,16 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { Account } from "../../models/loginModel.ts";
|
import { Account } from "@/src/models/loginModel";
|
||||||
import { areFriends } from "../../services/friendService.ts";
|
import { createMessage } from "@/src/services/inboxService";
|
||||||
import { createMessage } from "../../services/inboxService.ts";
|
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
import {
|
import { getAccountForRequest, getSuffixedName } from "@/src/services/loginService";
|
||||||
combineInventoryChanges,
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
getEffectiveAvatarImageType,
|
import { IPurchaseParams } from "@/src/types/purchaseTypes";
|
||||||
getInventory,
|
import { RequestHandler } from "express";
|
||||||
updateCurrency
|
import { ExportFlavour } from "warframe-public-export-plus";
|
||||||
} from "../../services/inventoryService.ts";
|
|
||||||
import { getAccountForRequest, getSuffixedName } from "../../services/loginService.ts";
|
|
||||||
import { handleDailyDealPurchase, handleStoreItemAcquisition } from "../../services/purchaseService.ts";
|
|
||||||
import type { IOid } from "../../types/commonTypes.ts";
|
|
||||||
import type { IPurchaseParams, IPurchaseResponse } from "../../types/purchaseTypes.ts";
|
|
||||||
import { PurchaseSource } from "../../types/purchaseTypes.ts";
|
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
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 (!checkPurchaseParams(data.PurchaseParams)) {
|
if (data.PurchaseParams.Source != 0 || !data.PurchaseParams.UsePremium) {
|
||||||
throw new Error(`unexpected purchase params in gifting request: ${String(req.body)}`);
|
throw new Error(`unexpected purchase params in gifting request: ${String(req.body)}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -49,11 +30,8 @@ export const giftingController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Cannot gift to players who have gifting disabled.
|
// Cannot gift to players who have gifting disabled.
|
||||||
const senderAccount = await getAccountForRequest(req);
|
// TODO: Also consider GIFT_MODE_FRIENDS once friends are implemented
|
||||||
if (
|
if (inventory.Settings?.GiftMode == "GIFT_MODE_NONE") {
|
||||||
inventory.Settings?.GiftMode == "GIFT_MODE_NONE" ||
|
|
||||||
(inventory.Settings?.GiftMode == "GIFT_MODE_FRIENDS" && !(await areFriends(account._id, senderAccount._id)))
|
|
||||||
) {
|
|
||||||
res.status(400).send("17").end();
|
res.status(400).send("17").end();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -62,7 +40,11 @@ export const giftingController: RequestHandler = async (req, res) => {
|
|||||||
// TODO: Cannot gift archwing items to players that have not completed the archwing quest. (Code 7)
|
// TODO: Cannot gift archwing items to players that have not completed the archwing quest. (Code 7)
|
||||||
// TODO: Cannot gift necramechs to players that have not completed heart of deimos. (Code 20)
|
// TODO: Cannot gift necramechs to players that have not completed heart of deimos. (Code 20)
|
||||||
|
|
||||||
const senderInventory = await getInventory(senderAccount._id.toString());
|
const senderAccount = await getAccountForRequest(req);
|
||||||
|
const senderInventory = await getInventory(
|
||||||
|
senderAccount._id.toString(),
|
||||||
|
"PremiumCredits PremiumCreditsFree ActiveAvatarImageType GiftsRemaining"
|
||||||
|
);
|
||||||
|
|
||||||
if (senderInventory.GiftsRemaining == 0) {
|
if (senderInventory.GiftsRemaining == 0) {
|
||||||
res.status(400).send("10").end();
|
res.status(400).send("10").end();
|
||||||
@ -70,23 +52,7 @@ export const giftingController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
senderInventory.GiftsRemaining -= 1;
|
senderInventory.GiftsRemaining -= 1;
|
||||||
|
|
||||||
const response: IPurchaseResponse = {
|
updateCurrency(senderInventory, data.PurchaseParams.ExpectedPrice, true);
|
||||||
InventoryChanges: {}
|
|
||||||
};
|
|
||||||
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) {
|
|
||||||
const bundle = ExportBundles[data.PurchaseParams.StoreItem];
|
|
||||||
if (bundle.giftingBonus) {
|
|
||||||
combineInventoryChanges(
|
|
||||||
response.InventoryChanges,
|
|
||||||
(await handleStoreItemAcquisition(bundle.giftingBonus, senderInventory)).InventoryChanges
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
await senderInventory.save();
|
await senderInventory.save();
|
||||||
|
|
||||||
const senderName = getSuffixedName(senderAccount);
|
const senderName = getSuffixedName(senderAccount);
|
||||||
@ -105,7 +71,7 @@ export const giftingController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
],
|
],
|
||||||
sub: "/Lotus/Language/Menu/GiftReceivedSubject",
|
sub: "/Lotus/Language/Menu/GiftReceivedSubject",
|
||||||
icon: ExportFlavour[getEffectiveAvatarImageType(senderInventory)].icon,
|
icon: ExportFlavour[senderInventory.ActiveAvatarImageType].icon,
|
||||||
gifts: [
|
gifts: [
|
||||||
{
|
{
|
||||||
GiftType: data.PurchaseParams.StoreItem
|
GiftType: data.PurchaseParams.StoreItem
|
||||||
@ -114,7 +80,7 @@ export const giftingController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
]);
|
]);
|
||||||
|
|
||||||
res.json(response);
|
res.end();
|
||||||
};
|
};
|
||||||
|
|
||||||
interface IGiftingRequest {
|
interface IGiftingRequest {
|
||||||
|
|||||||
@ -1,14 +1,11 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { broadcastInventoryUpdate } from "../../services/wsService.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { addMiscItems, getInventory } from "@/src/services/inventoryService";
|
||||||
import { addMiscItems, getInventory } from "../../services/inventoryService.ts";
|
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import type { TEquipmentKey } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { ArtifactPolarity, EquipmentFeatures, IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import type { ArtifactPolarity } from "../../types/inventoryTypes/commonInventoryTypes.ts";
|
|
||||||
import { ExportRecipes } from "warframe-public-export-plus";
|
import { ExportRecipes } from "warframe-public-export-plus";
|
||||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import type { IEquipmentClient } from "../../types/equipmentTypes.ts";
|
|
||||||
import { EquipmentFeatures } from "../../types/equipmentTypes.ts";
|
|
||||||
|
|
||||||
interface IGildWeaponRequest {
|
interface IGildWeaponRequest {
|
||||||
ItemName: string;
|
ItemName: string;
|
||||||
@ -75,5 +72,4 @@ export const gildWeaponController: RequestHandler = async (req, res) => {
|
|||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
AffiliationMods: affiliationMods
|
AffiliationMods: affiliationMods
|
||||||
});
|
});
|
||||||
broadcastInventoryUpdate(req);
|
|
||||||
};
|
};
|
||||||
|
|||||||
@ -1,17 +1,16 @@
|
|||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { parseString } from "../../helpers/general.ts";
|
import { parseString } from "@/src/helpers/general";
|
||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { giveKeyChainItem } from "../../services/questService.ts";
|
import { giveKeyChainItem } from "@/src/services/questService";
|
||||||
import type { IKeyChainRequest } from "../../types/requestTypes.ts";
|
import { IKeyChainRequest } from "@/src/types/requestTypes";
|
||||||
|
|
||||||
export const giveKeyChainTriggeredItemsController: RequestHandler = async (req, res) => {
|
export const giveKeyChainTriggeredItemsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = parseString(req.query.accountId);
|
const accountId = parseString(req.query.accountId);
|
||||||
const keyChainInfo = getJSONfromString<IKeyChainRequest>((req.body as string).toString());
|
const keyChainInfo = getJSONfromString<IKeyChainRequest>((req.body as string).toString());
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const questKey = inventory.QuestKeys.find(qk => qk.ItemType === keyChainInfo.KeyChain)!;
|
const inventoryChanges = await giveKeyChainItem(inventory, keyChainInfo);
|
||||||
const inventoryChanges = await giveKeyChainItem(inventory, keyChainInfo, questKey);
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.send(inventoryChanges);
|
res.send(inventoryChanges);
|
||||||
|
|||||||
@ -1,16 +1,15 @@
|
|||||||
import { getInventory } from "../../services/inventoryService.ts";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { giveKeyChainMessage } from "../../services/questService.ts";
|
import { giveKeyChainMessage } from "@/src/services/questService";
|
||||||
import type { IKeyChainRequest } from "../../types/requestTypes.ts";
|
import { IKeyChainRequest } from "@/src/types/requestTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const giveKeyChainTriggeredMessageController: RequestHandler = async (req, res) => {
|
export const giveKeyChainTriggeredMessageController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const keyChainInfo = JSON.parse((req.body as Buffer).toString()) as IKeyChainRequest;
|
const keyChainInfo = JSON.parse((req.body as Buffer).toString()) as IKeyChainRequest;
|
||||||
|
|
||||||
const inventory = await getInventory(accountId, "QuestKeys accountOwnerId");
|
const inventory = await getInventory(accountId, "QuestKeys");
|
||||||
const questKey = inventory.QuestKeys.find(qk => qk.ItemType === keyChainInfo.KeyChain)!;
|
await giveKeyChainMessage(inventory, accountId, keyChainInfo);
|
||||||
await giveKeyChainMessage(inventory, keyChainInfo, questKey);
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.send(1);
|
res.send(1);
|
||||||
|
|||||||
@ -1,8 +1,8 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { addItem, getInventory } from "../../services/inventoryService.ts";
|
import { addItem, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { IOid } from "../../types/commonTypes.ts";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import type { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const giveQuestKeyRewardController: RequestHandler = async (req, res) => {
|
export const giveQuestKeyRewardController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
@ -1,9 +1,8 @@
|
|||||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { addLoreFragmentScans, addShipDecorations, getInventory } from "../../services/inventoryService.ts";
|
import { addLoreFragmentScans, addShipDecorations, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import type { ITypeCount } from "../../types/commonTypes.ts";
|
import { ILoreFragmentScan, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import type { ILoreFragmentScan } from "../../types/inventoryTypes/inventoryTypes.ts";
|
import { RequestHandler } from "express";
|
||||||
import type { RequestHandler } from "express";
|
|
||||||
|
|
||||||
export const giveShipDecoAndLoreFragmentController: RequestHandler = async (req, res) => {
|
export const giveShipDecoAndLoreFragmentController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
|||||||
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