Compare commits
38 Commits
9ef852190c
...
11c085fcd7
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
11c085fcd7 | ||
|
|
bbbc554939 | ||
|
|
7ea9460b11 | ||
|
|
83b44e8e13 | ||
|
|
542694b576 | ||
|
|
94df06490f | ||
|
|
29afa68065 | ||
|
|
008b45df30 | ||
|
|
65fbd9c5fc | ||
|
|
4f0c9e9695 | ||
|
|
259bfd5800 | ||
|
|
4d03246e16 | ||
| 9662da00de | |||
| 662d824369 | |||
| a0bac12e95 | |||
| e98cb2ec24 | |||
| b5c6c3e485 | |||
| fa65ba3f25 | |||
| 0c54c064eb | |||
| b4e789bf0d | |||
| 9add016d7b | |||
| a2171c80a5 | |||
| 5a2fa2c2c3 | |||
| 4b2b184b8f | |||
| dc401de1e9 | |||
| 1439fdc083 | |||
| 6771a129f5 | |||
| f13de810e5 | |||
| c52f7dcedc | |||
| 0bf142ed50 | |||
| 0d791ad145 | |||
| 5396eefe75 | |||
| a9a197b005 | |||
| 1ade801e7c | |||
| c9cc1fa089 | |||
| 287acab892 | |||
| 30398021b3 | |||
| 15578b04d2 |
@ -3,3 +3,6 @@
|
||||
Dockerfile*
|
||||
.*
|
||||
docker-data/
|
||||
node_modules/
|
||||
static/data/
|
||||
logs/
|
||||
|
||||
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@ -12,14 +12,13 @@ jobs:
|
||||
- name: Setup Node.js environment
|
||||
uses: actions/setup-node@v4.0.2
|
||||
with:
|
||||
node-version: ">=20.6.0"
|
||||
node-version: ">=20.18.1"
|
||||
- run: npm ci
|
||||
- run: cp config-vanilla.json config.json
|
||||
- run: npm run verify
|
||||
- run: npm run lint:ci
|
||||
- run: npm run prettier
|
||||
- run: npm run update-translations
|
||||
- run: npm run fix-imports
|
||||
- name: Fail if there are uncommitted changes
|
||||
run: |
|
||||
if [[ -n "$(git status --porcelain)" ]]; then
|
||||
|
||||
3
.vscode/settings.json
vendored
Normal file
3
.vscode/settings.json
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
{
|
||||
"typescript.preferences.preferTypeOnlyAutoImports": true
|
||||
}
|
||||
@ -5,8 +5,7 @@ RUN apk add --no-cache bash jq
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm i --omit=dev
|
||||
RUN npm run build
|
||||
RUN npm i --omit=dev --omit=optional
|
||||
RUN date '+%d %B %Y' > BUILD_DATE
|
||||
|
||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||
|
||||
@ -2,24 +2,27 @@
|
||||
|
||||
echo Updating SpaceNinjaServer...
|
||||
git fetch --prune
|
||||
git stash
|
||||
git checkout -f origin/main
|
||||
|
||||
if exist static\data\0\ (
|
||||
echo Updating stripped assets...
|
||||
cd static\data\0\
|
||||
git pull
|
||||
cd ..\..\..\
|
||||
)
|
||||
|
||||
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.
|
||||
git stash
|
||||
git checkout -f origin/main
|
||||
|
||||
if exist static\data\0\ (
|
||||
echo Updating stripped assets...
|
||||
cd static\data\0\
|
||||
git pull
|
||||
cd ..\..\..\
|
||||
)
|
||||
|
||||
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
|
||||
pause > nul
|
||||
goto a
|
||||
|
||||
@ -2,22 +2,23 @@
|
||||
|
||||
echo "Updating SpaceNinjaServer..."
|
||||
git fetch --prune
|
||||
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..."
|
||||
npm i --omit=dev
|
||||
|
||||
npm run build
|
||||
if [ $? -eq 0 ]; then
|
||||
npm run start
|
||||
echo "SpaceNinjaServer seems to have crashed."
|
||||
fi
|
||||
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..."
|
||||
npm i --omit=dev
|
||||
|
||||
npm run build
|
||||
if [ $? -eq 0 ]; then
|
||||
npm run start
|
||||
echo "SpaceNinjaServer seems to have crashed."
|
||||
fi
|
||||
fi
|
||||
|
||||
@ -11,7 +11,6 @@
|
||||
"administratorNames": [],
|
||||
"autoCreateAccount": true,
|
||||
"skipTutorial": false,
|
||||
"skipAllDialogue": false,
|
||||
"unlockAllScans": false,
|
||||
"unlockAllShipFeatures": false,
|
||||
"unlockAllShipDecorations": false,
|
||||
@ -19,9 +18,6 @@
|
||||
"unlockAllSkins": false,
|
||||
"unlockAllCapturaScenes": false,
|
||||
"fullyStockedVendors": false,
|
||||
"baroAlwaysAvailable": false,
|
||||
"baroFullyStocked": false,
|
||||
"unlockAllProfitTakerStages": false,
|
||||
"skipClanKeyCrafting": false,
|
||||
"noDojoRoomBuildStage": false,
|
||||
"noDecoBuildStage": false,
|
||||
@ -29,9 +25,7 @@
|
||||
"noDojoResearchCosts": false,
|
||||
"noDojoResearchTime": false,
|
||||
"fastClanAscension": false,
|
||||
"missionsCanGiveAllRelics": false,
|
||||
"unlockAllSimarisResearchEntries": false,
|
||||
"disableDailyTribute": false,
|
||||
"spoofMasteryRank": -1,
|
||||
"relicRewardItemCountMultiplier": 1,
|
||||
"nightwaveStandingMultiplier": 1,
|
||||
@ -45,6 +39,10 @@
|
||||
"affinityBoost": false,
|
||||
"resourceBoost": false,
|
||||
"tennoLiveRelay": false,
|
||||
"baroTennoConRelay": false,
|
||||
"baroAlwaysAvailable": false,
|
||||
"baroFullyStocked": false,
|
||||
"varziaFullyStocked": false,
|
||||
"wolfHunt": false,
|
||||
"orphixVenom": false,
|
||||
"longShadow": false,
|
||||
@ -71,10 +69,9 @@
|
||||
"duviriOverride": "",
|
||||
"nightwaveOverride": "",
|
||||
"allTheFissures": "",
|
||||
"circuitGameModes": null,
|
||||
"darvoStockMultiplier": 1,
|
||||
"varziaOverride": "",
|
||||
"varziaFullyStocked": false
|
||||
"circuitGameModes": null,
|
||||
"darvoStockMultiplier": 1
|
||||
},
|
||||
"dev": {
|
||||
"keepVendorsExpired": false
|
||||
|
||||
@ -5,4 +5,4 @@ if [ ! -f conf/config.json ]; then
|
||||
jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config-vanilla.json > /app/conf/config.json
|
||||
fi
|
||||
|
||||
exec npm run start -- --configPath conf/config.json
|
||||
exec npm run raw -- --configPath conf/config.json
|
||||
|
||||
41
package-lock.json
generated
41
package-lock.json
generated
@ -9,11 +9,6 @@
|
||||
"version": "0.1.0",
|
||||
"license": "GNU",
|
||||
"dependencies": {
|
||||
"@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",
|
||||
"chokidar": "^4.0.3",
|
||||
"crc-32": "^1.2.2",
|
||||
"express": "^5",
|
||||
@ -21,7 +16,6 @@
|
||||
"mongoose": "^8.11.0",
|
||||
"morgan": "^1.10.0",
|
||||
"ncp": "^2.0.0",
|
||||
"typescript": "^5.7",
|
||||
"undici": "^7.10.0",
|
||||
"warframe-public-export-plus": "^0.5.83",
|
||||
"warframe-riven-info": "^0.1.2",
|
||||
@ -38,6 +32,14 @@
|
||||
"eslint-plugin-prettier": "^5.2.5",
|
||||
"prettier": "^3.5.3",
|
||||
"tree-kill": "^1.2.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"
|
||||
}
|
||||
},
|
||||
"node_modules/@colors/colors": {
|
||||
@ -349,6 +351,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.6.tgz",
|
||||
"integrity": "sha512-HLFeCYgz89uk22N5Qg3dvGvsv46B8GLvKKo1zKG4NybA8U2DiEO3w9lqGg29t/tfLRJpJ6iQxnVw4OnB7MoM9g==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/connect": "*",
|
||||
"@types/node": "*"
|
||||
@ -359,6 +362,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/connect/-/connect-3.4.38.tgz",
|
||||
"integrity": "sha512-K6uROf1LD88uDQqJCktA4yzL1YYAK6NgfsI0v/mTgyPKWsX1CnJ0XPSDhViejru1GcRkLWb8RlzFYJRqGUbaug==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@ -368,6 +372,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/express/-/express-5.0.3.tgz",
|
||||
"integrity": "sha512-wGA0NX93b19/dZC1J18tKWVIYWyyF2ZjT9vin/NRu0qzzvfVzWjs04iq2rQ3H65vCTQYlRqs3YHfY7zjdV+9Kw==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/body-parser": "*",
|
||||
"@types/express-serve-static-core": "^5.0.0",
|
||||
@ -379,6 +384,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/express-serve-static-core/-/express-serve-static-core-5.0.7.tgz",
|
||||
"integrity": "sha512-R+33OsgWw7rOhD1emjU7dzCDHucJrgJXMA5PYCzJxVil0dsyx5iBEPHqpPfiKNJQb7lZ1vxwoLR4Z87bBUpeGQ==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*",
|
||||
"@types/qs": "*",
|
||||
@ -390,7 +396,8 @@
|
||||
"version": "2.0.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/http-errors/-/http-errors-2.0.5.tgz",
|
||||
"integrity": "sha512-r8Tayk8HJnX0FztbZN7oVqGccWgw98T/0neJphO91KkmOzug1KkofZURD4UaD5uH8AqcFLfdPErnBod0u71/qg==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/json5": {
|
||||
"version": "0.0.29",
|
||||
@ -403,13 +410,15 @@
|
||||
"version": "1.3.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.5.tgz",
|
||||
"integrity": "sha512-/pyBZWSLD2n0dcHE3hq8s8ZvcETHtEuF+3E7XVt0Ig2nvsVQXdghHVcEkIWjy9A0wKfTn97a/PSDYohKIlnP/w==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/morgan": {
|
||||
"version": "1.9.10",
|
||||
"resolved": "https://registry.npmjs.org/@types/morgan/-/morgan-1.9.10.tgz",
|
||||
"integrity": "sha512-sS4A1zheMvsADRVfT0lYbJ4S9lmsey8Zo2F7cnbYjWHP67Q0AwMYuuzLlkIM2N8gAbb9cubhIVFwcIN2XyYCkA==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@ -419,6 +428,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/node/-/node-24.3.0.tgz",
|
||||
"integrity": "sha512-aPTXCrfwnDLj4VvXrm+UUCQjNEvJgNA8s5F1cvwQU+3KNltTOkBm1j30uNLyqqPNe7gE3KFzImYoZEfLhp4Yow==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"undici-types": "~7.10.0"
|
||||
}
|
||||
@ -427,19 +437,22 @@
|
||||
"version": "6.14.0",
|
||||
"resolved": "https://registry.npmjs.org/@types/qs/-/qs-6.14.0.tgz",
|
||||
"integrity": "sha512-eOunJqu0K1923aExK6y8p6fsihYEn/BYuQ4g0CxAAgFc4b/ZLN4CrsRZ55srTdqoiLzU2B2evC+apEIxprEzkQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/range-parser": {
|
||||
"version": "1.2.7",
|
||||
"resolved": "https://registry.npmjs.org/@types/range-parser/-/range-parser-1.2.7.tgz",
|
||||
"integrity": "sha512-hKormJbkJqzQGhziax5PItDUTMAM9uE2XXQmM37dyd4hVM+5aVl7oVxMVUiVQn2oCQFN/LKCZdvSM0pFRqbSmQ==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/@types/send": {
|
||||
"version": "0.17.5",
|
||||
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.5.tgz",
|
||||
"integrity": "sha512-z6F2D3cOStZvuk2SaP6YrwkNO65iTZcwA2ZkSABegdkAh/lf+Aa/YQndZVfmEXT5vgAp6zv06VQ3ejSVjAny4w==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/mime": "^1",
|
||||
"@types/node": "*"
|
||||
@ -450,6 +463,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/serve-static/-/serve-static-1.15.8.tgz",
|
||||
"integrity": "sha512-roei0UY3LhpOJvjbIP6ZZFngyLKl5dskOtDhxY5THRSpO+ZI+nzJ+m5yUMzGrp89YRa7lvknKkMYjqQFGwA7Sg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/http-errors": "*",
|
||||
"@types/node": "*",
|
||||
@ -473,6 +487,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/websocket/-/websocket-1.0.10.tgz",
|
||||
"integrity": "sha512-svjGZvPB7EzuYS94cI7a+qhwgGU1y89wUgjT6E2wVUfmAGIvRfT7obBvRtnhXCSsoMdlG4gBFGE7MfkIXZLoww==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@ -491,6 +506,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
|
||||
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
|
||||
"license": "MIT",
|
||||
"optional": true,
|
||||
"dependencies": {
|
||||
"@types/node": "*"
|
||||
}
|
||||
@ -735,6 +751,7 @@
|
||||
"resolved": "https://registry.npmjs.org/@typescript/native-preview/-/native-preview-7.0.0-dev.20250826.1.tgz",
|
||||
"integrity": "sha512-+NuzOfk/lu6pLYSCio+R7uzJ9pfOasc1fshxVmLp6wgcB8yuUYYvBaT7CoHapUnNBYZXkJ9u0UOECnq3dbzgSQ==",
|
||||
"license": "Apache-2.0",
|
||||
"optional": true,
|
||||
"bin": {
|
||||
"tsgo": "bin/tsgo.js"
|
||||
},
|
||||
@ -5397,6 +5414,7 @@
|
||||
"version": "5.9.2",
|
||||
"resolved": "https://registry.npmjs.org/typescript/-/typescript-5.9.2.tgz",
|
||||
"integrity": "sha512-CWBzXQrc/qOkhidw1OzBTQuYRbfyxDXJMVJ1XNwUHGROVmuaeiEm3OslpZ1RV96d7SKKjZKrSJu3+t/xlw3R9A==",
|
||||
"devOptional": true,
|
||||
"license": "Apache-2.0",
|
||||
"bin": {
|
||||
"tsc": "bin/tsc",
|
||||
@ -5438,7 +5456,8 @@
|
||||
"version": "7.10.0",
|
||||
"resolved": "https://registry.npmjs.org/undici-types/-/undici-types-7.10.0.tgz",
|
||||
"integrity": "sha512-t5Fy/nfn+14LuOc2KNYg75vZqClpAiqscVvMygNnlsHBFpSXdJaYtXMcdNLpl/Qvc3P2cB3s6lOV51nqsFq4ag==",
|
||||
"license": "MIT"
|
||||
"license": "MIT",
|
||||
"optional": true
|
||||
},
|
||||
"node_modules/unpipe": {
|
||||
"version": "1.0.0",
|
||||
|
||||
20
package.json
20
package.json
@ -22,17 +22,11 @@
|
||||
"lint:fix": "eslint --fix --ext .ts .",
|
||||
"prettier": "prettier --write .",
|
||||
"update-translations": "cd scripts && node update-translations.cjs",
|
||||
"fix-imports": "cd scripts && node fix-imports.cjs",
|
||||
"fix": "npm run update-translations && npm run fix-imports && npm run prettier"
|
||||
"fix": "npm run update-translations && npm run lint:fix"
|
||||
},
|
||||
"license": "GNU",
|
||||
"type": "module",
|
||||
"dependencies": {
|
||||
"@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",
|
||||
"chokidar": "^4.0.3",
|
||||
"crc-32": "^1.2.2",
|
||||
"express": "^5",
|
||||
@ -40,7 +34,6 @@
|
||||
"mongoose": "^8.11.0",
|
||||
"morgan": "^1.10.0",
|
||||
"ncp": "^2.0.0",
|
||||
"typescript": "^5.7",
|
||||
"undici": "^7.10.0",
|
||||
"warframe-public-export-plus": "^0.5.83",
|
||||
"warframe-riven-info": "^0.1.2",
|
||||
@ -48,6 +41,14 @@
|
||||
"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": {
|
||||
"@typescript-eslint/eslint-plugin": "^8.28.0",
|
||||
"@typescript-eslint/parser": "^8.28.0",
|
||||
@ -57,5 +58,8 @@
|
||||
"eslint-plugin-prettier": "^5.2.5",
|
||||
"prettier": "^3.5.3",
|
||||
"tree-kill": "^1.2.2"
|
||||
},
|
||||
"engines": {
|
||||
"node": ">=20.18.1"
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,75 +0,0 @@
|
||||
/* eslint-disable */
|
||||
const fs = require("fs");
|
||||
const path = require("path");
|
||||
|
||||
const root = path.join(process.cwd(), "..");
|
||||
|
||||
function listFiles(dir) {
|
||||
const entries = fs.readdirSync(dir, { withFileTypes: true });
|
||||
let results = [];
|
||||
for (const entry of entries) {
|
||||
const fullPath = path.join(dir, entry.name);
|
||||
if (entry.isDirectory()) {
|
||||
results = results.concat(listFiles(fullPath));
|
||||
} else {
|
||||
results.push(fullPath);
|
||||
}
|
||||
}
|
||||
return results;
|
||||
}
|
||||
|
||||
const files = listFiles(path.join(root, "src"));
|
||||
|
||||
for (const file of files) {
|
||||
let content;
|
||||
try {
|
||||
content = fs.readFileSync(file, "utf8");
|
||||
} catch (e) {
|
||||
continue;
|
||||
}
|
||||
const dir = path.dirname(file);
|
||||
const fixedContent = content.replaceAll(/from "([^"]+)";/g, (sub, importPath) => {
|
||||
if (importPath.startsWith("@/") || importPath.startsWith(".")) {
|
||||
const base = importPath.startsWith("@/")
|
||||
? path.join(root, importPath.slice(2))
|
||||
: path.resolve(dir, importPath);
|
||||
let target = base;
|
||||
|
||||
if (fs.existsSync(target)) {
|
||||
const stat = fs.statSync(target);
|
||||
if (stat.isDirectory()) {
|
||||
if (fs.existsSync(path.join(target, "index.ts"))) {
|
||||
target = path.join(target, "index.ts");
|
||||
} else {
|
||||
return sub;
|
||||
}
|
||||
} else {
|
||||
const ext = path.extname(target);
|
||||
if (!ext) {
|
||||
target += ".ts";
|
||||
}
|
||||
}
|
||||
} else if (fs.existsSync(target + ".ts")) {
|
||||
target += ".ts";
|
||||
} else if (fs.existsSync(path.join(target, "index.ts"))) {
|
||||
target = path.join(target, "index.ts");
|
||||
} else {
|
||||
return sub;
|
||||
}
|
||||
|
||||
let relative = path.relative(dir, target).replace(/\\/g, "/");
|
||||
if (!path.extname(relative)) {
|
||||
relative += ".ts";
|
||||
}
|
||||
if (!relative.startsWith(".")) {
|
||||
relative = "./" + relative;
|
||||
}
|
||||
console.log(`${importPath} -> ${relative}`);
|
||||
return sub.split(importPath).join(relative);
|
||||
}
|
||||
return sub;
|
||||
});
|
||||
if (content != fixedContent) {
|
||||
fs.writeFileSync(file, fixedContent, "utf8");
|
||||
}
|
||||
}
|
||||
@ -31,7 +31,7 @@ fs.readdirSync("../static/webui/translations").forEach(file => {
|
||||
const strings = extractStrings(line);
|
||||
if (Object.keys(strings).length > 0) {
|
||||
Object.entries(strings).forEach(([key, value]) => {
|
||||
if (targetStrings.hasOwnProperty(key) && !targetStrings[key].startsWith("[UNTRANSLATED] ")) {
|
||||
if (targetStrings.hasOwnProperty(key) && !targetStrings[key].startsWith("[UNTRANSLATED]")) {
|
||||
fs.writeSync(fileHandle, ` ${key}: \`${targetStrings[key]}\`,\n`);
|
||||
} else {
|
||||
fs.writeSync(fileHandle, ` ${key}: \`[UNTRANSLATED] ${value}\`,\n`);
|
||||
|
||||
@ -13,8 +13,6 @@ import { payRouter } from "./routes/pay.ts";
|
||||
import { statsRouter } from "./routes/stats.ts";
|
||||
import { webuiRouter } from "./routes/webui.ts";
|
||||
|
||||
import { worldStateController } from "./controllers/dynamic/worldStateController.ts";
|
||||
|
||||
const app = express();
|
||||
|
||||
app.use((req, _res, next) => {
|
||||
@ -47,9 +45,6 @@ app.use("/pay", payRouter);
|
||||
app.use("/stats", statsRouter);
|
||||
app.use("/", webuiRouter);
|
||||
|
||||
// U39.1+ gets worldState from that location
|
||||
app.get("/worldState.php", worldStateController);
|
||||
|
||||
app.use(unknownEndpointHandler);
|
||||
app.use(errorHandler);
|
||||
|
||||
|
||||
@ -4,8 +4,9 @@
|
||||
import type { RequestHandler } from "express";
|
||||
import { logger } from "../../utils/logger.ts";
|
||||
import { getRecipe } from "../../services/itemDataService.ts";
|
||||
import type { IOid, IOidWithLegacySupport } from "../../types/commonTypes.ts";
|
||||
import type { IOidWithLegacySupport } from "../../types/commonTypes.ts";
|
||||
import { getJSONfromString } from "../../helpers/stringHelpers.ts";
|
||||
import type { TAccountDocument } from "../../services/loginService.ts";
|
||||
import { getAccountForRequest } from "../../services/loginService.ts";
|
||||
import {
|
||||
getInventory,
|
||||
@ -21,240 +22,254 @@ import {
|
||||
import type { IInventoryChanges } from "../../types/purchaseTypes.ts";
|
||||
import type { IPendingRecipeDatabase } from "../../types/inventoryTypes/inventoryTypes.ts";
|
||||
import { InventorySlot } from "../../types/inventoryTypes/inventoryTypes.ts";
|
||||
import { toOid2 } from "../../helpers/inventoryHelpers.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 {
|
||||
RecipeIds: IOid[];
|
||||
RecipeIds: IOidWithLegacySupport[];
|
||||
}
|
||||
|
||||
interface IClaimCompletedRecipeResponse {
|
||||
InventoryChanges: IInventoryChanges;
|
||||
BrandedSuits?: IOidWithLegacySupport[];
|
||||
}
|
||||
|
||||
export const claimCompletedRecipeController: RequestHandler = async (req, res) => {
|
||||
const claimCompletedRecipeRequest = getJSONfromString<IClaimCompletedRecipeRequest>(String(req.body));
|
||||
const account = await getAccountForRequest(req);
|
||||
const inventory = await getInventory(account._id.toString());
|
||||
const pendingRecipe = inventory.PendingRecipes.id(claimCompletedRecipeRequest.RecipeIds[0].$oid);
|
||||
if (!pendingRecipe) {
|
||||
throw new Error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`);
|
||||
}
|
||||
|
||||
//check recipe is indeed ready to be completed
|
||||
// if (pendingRecipe.CompletionDate > new Date()) {
|
||||
// throw new Error(`recipe ${pendingRecipe._id} is not ready to be completed`);
|
||||
// }
|
||||
|
||||
inventory.PendingRecipes.pull(pendingRecipe._id);
|
||||
|
||||
const recipe = getRecipe(pendingRecipe.ItemType);
|
||||
if (!recipe) {
|
||||
throw new Error(`no completed item found for recipe ${pendingRecipe._id.toString()}`);
|
||||
}
|
||||
|
||||
if (req.query.cancel) {
|
||||
const inventoryChanges: IInventoryChanges = {};
|
||||
await refundRecipeIngredients(inventory, inventoryChanges, recipe, pendingRecipe);
|
||||
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 | IOidWithLegacySupport[];
|
||||
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 = [toOid2(pendingRecipe.SuitToUnbrand!, account.BuildLabel)];
|
||||
const resp: IClaimCompletedRecipeResponse = {
|
||||
InventoryChanges: {}
|
||||
};
|
||||
for (const recipeId of claimCompletedRecipeRequest.RecipeIds) {
|
||||
const pendingRecipe = inventory.PendingRecipes.id(fromOid(recipeId));
|
||||
if (!pendingRecipe) {
|
||||
throw new Error(`no pending recipe found with id ${fromOid(recipeId)}`);
|
||||
}
|
||||
|
||||
let InventoryChanges: IInventoryChanges = {};
|
||||
if (recipe.consumeOnUse) {
|
||||
addRecipes(inventory, [
|
||||
//check recipe is indeed ready to be completed
|
||||
// if (pendingRecipe.CompletionDate > new Date()) {
|
||||
// throw new Error(`recipe ${pendingRecipe._id} is not ready to be completed`);
|
||||
// }
|
||||
|
||||
inventory.PendingRecipes.pull(pendingRecipe._id);
|
||||
|
||||
const recipe = getRecipe(pendingRecipe.ItemType);
|
||||
if (!recipe) {
|
||||
throw new Error(`no completed item found for recipe ${pendingRecipe._id.toString()}`);
|
||||
}
|
||||
|
||||
if (req.query.cancel) {
|
||||
const inventoryChanges: IInventoryChanges = {};
|
||||
await refundRecipeIngredients(inventory, inventoryChanges, recipe, pendingRecipe);
|
||||
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",
|
||||
{
|
||||
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 =
|
||||
progress > 0.5
|
||||
? Math.round(recipe.skipBuildTimePrice * (1 - (progress - 0.5)))
|
||||
: recipe.skipBuildTimePrice;
|
||||
InventoryChanges = {
|
||||
...InventoryChanges,
|
||||
...updateCurrency(inventory, cost, true)
|
||||
};
|
||||
}
|
||||
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
|
||||
});
|
||||
|
||||
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, 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];
|
||||
InventoryChanges.Upgrades ??= [];
|
||||
InventoryChanges.Upgrades.push(umbraModA, umbraModB, umbraModC, sacrificeModA, sacrificeModB);
|
||||
|
||||
await addPowerSuit(
|
||||
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,
|
||||
"/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
|
||||
{
|
||||
Configs: [
|
||||
{
|
||||
Upgrades: [
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
"",
|
||||
umbraModA.ItemId.$oid,
|
||||
umbraModB.ItemId.$oid,
|
||||
umbraModC.ItemId.$oid
|
||||
]
|
||||
}
|
||||
],
|
||||
XP: 900_000,
|
||||
Features: EquipmentFeatures.DOUBLE_CAPACITY
|
||||
},
|
||||
InventoryChanges
|
||||
);
|
||||
inventory.XPInfo.push({
|
||||
ItemType: "/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
|
||||
XP: 900_000
|
||||
});
|
||||
|
||||
addEquipment(
|
||||
inventory,
|
||||
"Melee",
|
||||
"/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
|
||||
{
|
||||
Configs: [
|
||||
{ Upgrades: ["", "", "", "", "", "", sacrificeModA.ItemId.$oid, sacrificeModB.ItemId.$oid] }
|
||||
],
|
||||
XP: 450_000,
|
||||
Features: EquipmentFeatures.DOUBLE_CAPACITY
|
||||
},
|
||||
InventoryChanges
|
||||
);
|
||||
inventory.XPInfo.push({
|
||||
ItemType: "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
|
||||
XP: 450_000
|
||||
});
|
||||
} else {
|
||||
InventoryChanges = {
|
||||
...InventoryChanges,
|
||||
...(await addItem(
|
||||
inventory,
|
||||
recipe.resultType,
|
||||
recipe.num,
|
||||
false,
|
||||
undefined,
|
||||
pendingRecipe.TargetFingerprint
|
||||
))
|
||||
};
|
||||
}
|
||||
recipe.resultType,
|
||||
recipe.num,
|
||||
false,
|
||||
undefined,
|
||||
pendingRecipe.TargetFingerprint
|
||||
)
|
||||
);
|
||||
}
|
||||
if (
|
||||
inventory.claimingBlueprintRefundsIngredients &&
|
||||
recipe.secretIngredientAction != "SIA_CREATE_KUBROW" // Can't refund the egg
|
||||
) {
|
||||
await refundRecipeIngredients(inventory, InventoryChanges, recipe, pendingRecipe);
|
||||
}
|
||||
await inventory.save();
|
||||
res.json({ InventoryChanges, BrandedSuits });
|
||||
}
|
||||
if (
|
||||
inventory.claimingBlueprintRefundsIngredients &&
|
||||
recipe.secretIngredientAction != "SIA_CREATE_KUBROW" // Can't refund the egg
|
||||
) {
|
||||
await refundRecipeIngredients(inventory, resp.InventoryChanges, recipe, pendingRecipe);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@ -81,7 +81,7 @@ export const crewShipFusionController: RequestHandler = async (req, res) => {
|
||||
const newFval = (newPerc - rangeA[0]) / (rangeA[1] - rangeA[0]);
|
||||
buffA.Value = Math.trunc(newFval * 0x3fffffff);
|
||||
}
|
||||
if (inferiorFingerprint.SubroutineIndex) {
|
||||
if (inferiorFingerprint.SubroutineIndex !== undefined) {
|
||||
const useSuperiorSubroutine = tierA < tierB ? !payload.UseSubroutineA : payload.UseSubroutineA;
|
||||
if (!useSuperiorSubroutine) {
|
||||
fingerprint.SubroutineIndex = inferiorFingerprint.SubroutineIndex;
|
||||
|
||||
@ -306,7 +306,7 @@ export const getInventoryResponse = async (
|
||||
inventoryResponse.PrimeTokens = 999999999;
|
||||
}
|
||||
|
||||
if (config.skipAllDialogue) {
|
||||
if (inventory.skipAllDialogue) {
|
||||
inventoryResponse.TauntHistory = [
|
||||
{
|
||||
node: "TreasureTutorial",
|
||||
@ -486,42 +486,9 @@ export const getInventoryResponse = async (
|
||||
}
|
||||
}
|
||||
|
||||
if (config.unlockAllProfitTakerStages) {
|
||||
inventoryResponse.CompletedJobChains ??= [];
|
||||
const EudicoHeists = inventoryResponse.CompletedJobChains.find(x => x.LocationTag == "EudicoHeists");
|
||||
if (EudicoHeists) {
|
||||
EudicoHeists.Jobs = allEudicoHeistJobs;
|
||||
} else {
|
||||
inventoryResponse.CompletedJobChains.push({
|
||||
LocationTag: "EudicoHeists",
|
||||
Jobs: allEudicoHeistJobs
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
if (config.unlockAllSimarisResearchEntries) {
|
||||
inventoryResponse.LibraryPersonalTarget = undefined;
|
||||
inventoryResponse.LibraryPersonalProgress = [
|
||||
"/Lotus/Types/Game/Library/Targets/Research1Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research2Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research3Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research4Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research5Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research6Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research7Target"
|
||||
].map(type => ({ TargetType: type, Scans: 10, Completed: true }));
|
||||
}
|
||||
|
||||
return inventoryResponse;
|
||||
};
|
||||
|
||||
const allEudicoHeistJobs = [
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyOne",
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyTwo",
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyThree",
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyFour"
|
||||
];
|
||||
|
||||
const getExpRequiredForMr = (rank: number): number => {
|
||||
if (rank <= 30) {
|
||||
return 2500 * rank * rank;
|
||||
|
||||
@ -140,7 +140,11 @@ const createLoginResponse = (
|
||||
resp.MatchmakingBuildId = buildConfig.matchmakingBuildId;
|
||||
}
|
||||
if (version_compare(buildLabel, "2023.04.25.23.40") >= 0) {
|
||||
resp.platformCDNs = [`${myUrlBase}/`];
|
||||
if (version_compare(buildLabel, "2025.08.26.09.49") >= 0) {
|
||||
resp.platformCDNs = [`${myUrlBase}/dynamic/`];
|
||||
} else {
|
||||
resp.platformCDNs = [`${myUrlBase}/`];
|
||||
}
|
||||
}
|
||||
return resp;
|
||||
};
|
||||
|
||||
@ -8,7 +8,6 @@ import {
|
||||
setAccountGotLoginRewardToday
|
||||
} from "../../services/loginRewardService.ts";
|
||||
import { getInventory } from "../../services/inventoryService.ts";
|
||||
import { config } from "../../services/configService.ts";
|
||||
import { sendWsBroadcastTo } from "../../services/wsService.ts";
|
||||
|
||||
export const loginRewardsController: RequestHandler = async (req, res) => {
|
||||
@ -17,41 +16,42 @@ export const loginRewardsController: RequestHandler = async (req, res) => {
|
||||
const isMilestoneDay = account.LoginDays == 5 || account.LoginDays % 50 == 0;
|
||||
const nextMilestoneDay = account.LoginDays < 5 ? 5 : (Math.trunc(account.LoginDays / 50) + 1) * 50;
|
||||
|
||||
if (today == account.LastLoginRewardDate || config.disableDailyTribute) {
|
||||
res.json({
|
||||
DailyTributeInfo: {
|
||||
IsMilestoneDay: isMilestoneDay,
|
||||
IsChooseRewardSet: isLoginRewardAChoice(account),
|
||||
LoginDays: account.LoginDays,
|
||||
NextMilestoneReward: "",
|
||||
NextMilestoneDay: nextMilestoneDay
|
||||
}
|
||||
} satisfies ILoginRewardsReponse);
|
||||
return;
|
||||
}
|
||||
if (today != account.LastLoginRewardDate) {
|
||||
const inventory = await getInventory(account._id.toString());
|
||||
if (!inventory.disableDailyTribute) {
|
||||
const randomRewards = getRandomLoginRewards(account, inventory);
|
||||
const response: ILoginRewardsReponse = {
|
||||
DailyTributeInfo: {
|
||||
Rewards: randomRewards,
|
||||
IsMilestoneDay: isMilestoneDay,
|
||||
IsChooseRewardSet: randomRewards.length != 1,
|
||||
LoginDays: account.LoginDays,
|
||||
NextMilestoneReward: "",
|
||||
NextMilestoneDay: nextMilestoneDay,
|
||||
HasChosenReward: false
|
||||
},
|
||||
LastLoginRewardDate: today
|
||||
};
|
||||
if (!isMilestoneDay && randomRewards.length == 1) {
|
||||
response.DailyTributeInfo.HasChosenReward = true;
|
||||
response.DailyTributeInfo.ChosenReward = randomRewards[0];
|
||||
response.DailyTributeInfo.NewInventory = await claimLoginReward(inventory, randomRewards[0]);
|
||||
setAccountGotLoginRewardToday(account);
|
||||
await Promise.all([inventory.save(), account.save()]);
|
||||
|
||||
const inventory = await getInventory(account._id.toString());
|
||||
const randomRewards = getRandomLoginRewards(account, inventory);
|
||||
const response: ILoginRewardsReponse = {
|
||||
sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
|
||||
}
|
||||
res.json(response);
|
||||
return;
|
||||
}
|
||||
}
|
||||
res.json({
|
||||
DailyTributeInfo: {
|
||||
Rewards: randomRewards,
|
||||
IsMilestoneDay: isMilestoneDay,
|
||||
IsChooseRewardSet: randomRewards.length != 1,
|
||||
IsChooseRewardSet: isLoginRewardAChoice(account),
|
||||
LoginDays: account.LoginDays,
|
||||
NextMilestoneReward: "",
|
||||
NextMilestoneDay: nextMilestoneDay,
|
||||
HasChosenReward: false
|
||||
},
|
||||
LastLoginRewardDate: today
|
||||
};
|
||||
if (!isMilestoneDay && randomRewards.length == 1) {
|
||||
response.DailyTributeInfo.HasChosenReward = true;
|
||||
response.DailyTributeInfo.ChosenReward = randomRewards[0];
|
||||
response.DailyTributeInfo.NewInventory = await claimLoginReward(inventory, randomRewards[0]);
|
||||
setAccountGotLoginRewardToday(account);
|
||||
await Promise.all([inventory.save(), account.save()]);
|
||||
|
||||
sendWsBroadcastTo(account._id.toString(), { update_inventory: true });
|
||||
}
|
||||
res.json(response);
|
||||
NextMilestoneDay: nextMilestoneDay
|
||||
}
|
||||
} satisfies ILoginRewardsReponse);
|
||||
};
|
||||
|
||||
@ -95,6 +95,16 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
||||
ConquestCompletedMissionsCount
|
||||
} = await addMissionRewards(account, inventory, missionReport, firstCompletion);
|
||||
|
||||
const extraMissionRewards = inventory.extraMissionRewards ?? 0;
|
||||
if (extraMissionRewards >= 1) {
|
||||
for (let i = 0; i < extraMissionRewards; i++) {
|
||||
const rngMissionReport = missionReport;
|
||||
rngMissionReport.RewardInfo!.rewardSeed = generateRewardSeed();
|
||||
logger.debug("extra mission rewards with new seed, this might mismatch the mission report.");
|
||||
await addMissionRewards(account, inventory, rngMissionReport, firstCompletion);
|
||||
}
|
||||
}
|
||||
|
||||
if (missionReport.EndOfMatchUpload) {
|
||||
inventory.RewardSeed = generateRewardSeed();
|
||||
}
|
||||
|
||||
@ -47,6 +47,9 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
||||
const destFingerprint = JSON.parse(destWeapon.UpgradeFingerprint!) as IInnateDamageFingerprint;
|
||||
const sourceFingerprint = JSON.parse(sourceWeapon.UpgradeFingerprint!) as IInnateDamageFingerprint;
|
||||
|
||||
const fusionMultiplier = (await getInventory(account._id.toString(), "nemesisWeaponFusionMultiplier"))
|
||||
.nemesisWeaponFusionMultiplier;
|
||||
|
||||
// Update destination damage type if desired
|
||||
if (body.UseSourceDmgType) {
|
||||
destFingerprint.buffs[0].Tag = sourceFingerprint.buffs[0].Tag;
|
||||
@ -55,7 +58,7 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
||||
// Upgrade destination damage value
|
||||
const destDamage = 0.25 + (destFingerprint.buffs[0].Value / 0x3fffffff) * (0.6 - 0.25);
|
||||
const sourceDamage = 0.25 + (sourceFingerprint.buffs[0].Value / 0x3fffffff) * (0.6 - 0.25);
|
||||
let newDamage = Math.max(destDamage, sourceDamage) * 1.1;
|
||||
let newDamage = Math.max(destDamage, sourceDamage) * 1.1 * (fusionMultiplier ?? 1);
|
||||
if (newDamage >= 0.5794998) {
|
||||
newDamage = 0.6;
|
||||
}
|
||||
@ -101,9 +104,16 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
||||
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
|
||||
);
|
||||
const body = getJSONfromString<INemesisRequiemRequest>(String(req.body));
|
||||
const alwaysCorrectCheat = (await getInventory(account._id.toString(), "nemesisAlwaysCorrect"))
|
||||
.nemesisAlwaysCorrect;
|
||||
if (inventory.Nemesis!.Faction == "FC_INFESTATION") {
|
||||
const guess: number[] = [body.guess & 0xf, (body.guess >> 4) & 0xf, (body.guess >> 8) & 0xf];
|
||||
const passcode = getNemesisPasscode(inventory.Nemesis!)[0];
|
||||
|
||||
if (alwaysCorrectCheat) {
|
||||
guess[0] = guess[1] = guess[2] = passcode;
|
||||
}
|
||||
|
||||
const result1 = passcode == guess[0] ? GUESS_CORRECT : GUESS_INCORRECT;
|
||||
const result2 = passcode == guess[1] ? GUESS_CORRECT : GUESS_INCORRECT;
|
||||
const result3 = passcode == guess[2] ? GUESS_CORRECT : GUESS_INCORRECT;
|
||||
@ -149,7 +159,10 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
||||
break;
|
||||
}
|
||||
}
|
||||
inventory.Nemesis!.HenchmenKilled += antivirusGain;
|
||||
const antivirusGainMultiplier = (
|
||||
await getInventory(account._id.toString(), "nemesisAntivirusGainMultiplier")
|
||||
).nemesisAntivirusGainMultiplier;
|
||||
inventory.Nemesis!.HenchmenKilled += antivirusGain * (antivirusGainMultiplier ?? 1);
|
||||
if (inventory.Nemesis!.HenchmenKilled >= 100) {
|
||||
inventory.Nemesis!.HenchmenKilled = 100;
|
||||
|
||||
@ -195,7 +208,9 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
||||
|
||||
// Evaluate guess
|
||||
const correct =
|
||||
body.guess == GUESS_WILDCARD || getNemesisPasscode(inventory.Nemesis!)[body.position] == body.guess;
|
||||
body.guess == GUESS_WILDCARD ||
|
||||
getNemesisPasscode(inventory.Nemesis!)[body.position] == body.guess ||
|
||||
alwaysCorrectCheat;
|
||||
|
||||
// Update entry
|
||||
const guess = decodeNemesisGuess(
|
||||
|
||||
16
src/controllers/api/upgradeOperatorController.ts
Normal file
16
src/controllers/api/upgradeOperatorController.ts
Normal file
@ -0,0 +1,16 @@
|
||||
import { getInventory, updateCurrency } from "../../services/inventoryService.ts";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import type { RequestHandler } from "express";
|
||||
|
||||
export const upgradeOperatorController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(
|
||||
accountId,
|
||||
"OperatorCustomizationSlotPurchases PremiumCredits PremiumCreditsFree"
|
||||
);
|
||||
inventory.OperatorCustomizationSlotPurchases ??= 0;
|
||||
inventory.OperatorCustomizationSlotPurchases += 1;
|
||||
const inventoryChanges = updateCurrency(inventory, 10, true);
|
||||
await inventory.save();
|
||||
res.json({ InventoryChanges: inventoryChanges });
|
||||
};
|
||||
@ -64,9 +64,9 @@ interface ItemLists {
|
||||
|
||||
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
||||
VPQ_BRONZE: "",
|
||||
VPQ_SILVER: " [Flawless]",
|
||||
VPQ_GOLD: " [Radiant]",
|
||||
VPQ_PLATINUM: " [Exceptional]"
|
||||
VPQ_SILVER: " [Exceptional]",
|
||||
VPQ_GOLD: " [Flawless]",
|
||||
VPQ_PLATINUM: " [Radiant]"
|
||||
};
|
||||
|
||||
/*const toTitleCase = (str: string): string => {
|
||||
|
||||
@ -7,12 +7,12 @@ export const setAccountCheatController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const payload = req.body as ISetAccountCheatRequest;
|
||||
const inventory = await getInventory(accountId, payload.key);
|
||||
inventory[payload.key] = payload.value;
|
||||
inventory[payload.key] = payload.value as never;
|
||||
await inventory.save();
|
||||
res.end();
|
||||
};
|
||||
|
||||
interface ISetAccountCheatRequest {
|
||||
key: keyof IAccountCheats;
|
||||
value: boolean;
|
||||
value: boolean | number;
|
||||
}
|
||||
|
||||
@ -0,0 +1,24 @@
|
||||
import { getInventory } from "../../services/inventoryService.ts";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import type { RequestHandler } from "express";
|
||||
|
||||
const allEudicoHeistJobs = [
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyOne",
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyTwo",
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyThree",
|
||||
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyFour"
|
||||
];
|
||||
|
||||
export const unlockAllProfitTakerStagesController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(accountId, "CompletedJobChains");
|
||||
inventory.CompletedJobChains ??= [];
|
||||
const chain = inventory.CompletedJobChains.find(x => x.LocationTag == "EudicoHeists");
|
||||
if (chain) {
|
||||
chain.Jobs = allEudicoHeistJobs;
|
||||
} else {
|
||||
inventory.CompletedJobChains.push({ LocationTag: "EudicoHeists", Jobs: allEudicoHeistJobs });
|
||||
}
|
||||
await inventory.save();
|
||||
res.end();
|
||||
};
|
||||
@ -0,0 +1,20 @@
|
||||
import type { RequestHandler } from "express";
|
||||
import { getAccountIdForRequest } from "../../services/loginService.ts";
|
||||
import { getInventory } from "../../services/inventoryService.ts";
|
||||
|
||||
export const unlockAllSimarisResearchEntriesController: RequestHandler = async (req, res) => {
|
||||
const accountId = await getAccountIdForRequest(req);
|
||||
const inventory = await getInventory(accountId, "LibraryPersonalTarget LibraryPersonalProgress");
|
||||
inventory.LibraryPersonalTarget = undefined;
|
||||
inventory.LibraryPersonalProgress = [
|
||||
"/Lotus/Types/Game/Library/Targets/Research1Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research2Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research3Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research4Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research5Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research6Target",
|
||||
"/Lotus/Types/Game/Library/Targets/Research7Target"
|
||||
].map(type => ({ TargetType: type, Scans: 10, Completed: true }));
|
||||
await inventory.save();
|
||||
res.end();
|
||||
};
|
||||
@ -9,6 +9,7 @@ import { addMiscItems, combineInventoryChanges } from "../services/inventoryServ
|
||||
import { handleStoreItemAcquisition } from "../services/purchaseService.ts";
|
||||
import type { IInventoryChanges } from "../types/purchaseTypes.ts";
|
||||
import { config } from "../services/configService.ts";
|
||||
import { log } from "winston";
|
||||
|
||||
export const crackRelic = async (
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
@ -17,11 +18,11 @@ export const crackRelic = async (
|
||||
): Promise<IRngResult> => {
|
||||
const relic = ExportRelics[participant.VoidProjection];
|
||||
let weights = refinementToWeights[relic.quality];
|
||||
if (relic.quality == "VPQ_SILVER" && config.exceptionalRelicsAlwaysGiveBronzeReward) {
|
||||
if (relic.quality == "VPQ_SILVER" && inventory.exceptionalRelicsAlwaysGiveBronzeReward) {
|
||||
weights = { COMMON: 1, UNCOMMON: 0, RARE: 0, LEGENDARY: 0 };
|
||||
} else if (relic.quality == "VPQ_GOLD" && config.flawlessRelicsAlwaysGiveSilverReward) {
|
||||
} else if (relic.quality == "VPQ_GOLD" && inventory.flawlessRelicsAlwaysGiveSilverReward) {
|
||||
weights = { COMMON: 0, UNCOMMON: 1, RARE: 0, LEGENDARY: 0 };
|
||||
} else if (relic.quality == "VPQ_PLATINUM" && config.radiantRelicsAlwaysGiveGoldReward) {
|
||||
} else if (relic.quality == "VPQ_PLATINUM" && inventory.radiantRelicsAlwaysGiveGoldReward) {
|
||||
weights = { COMMON: 0, UNCOMMON: 0, RARE: 1, LEGENDARY: 0 };
|
||||
}
|
||||
logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights);
|
||||
@ -54,6 +55,26 @@ export const crackRelic = async (
|
||||
(await handleStoreItemAcquisition(reward.type, inventory, reward.itemCount)).InventoryChanges
|
||||
);
|
||||
|
||||
if (inventory.crackRelicForPlatinum) {
|
||||
let platinumReward = 0;
|
||||
switch (reward.rarity) {
|
||||
case "COMMON":
|
||||
platinumReward = inventory.relicPlatinumCommon ?? 2;
|
||||
break;
|
||||
case "UNCOMMON":
|
||||
platinumReward = inventory.relicPlatinumUncommon ?? 5;
|
||||
break;
|
||||
case "RARE":
|
||||
platinumReward = inventory.relicPlatinumRare ?? 12;
|
||||
break;
|
||||
case "LEGENDARY":
|
||||
logger.warn(`got a legendary reward for a relic!`);
|
||||
break;
|
||||
}
|
||||
logger.debug(`adding ${platinumReward} platinum to inventory for a ${reward.rarity} reward`);
|
||||
inventory.PremiumCredits += platinumReward;
|
||||
}
|
||||
|
||||
return reward;
|
||||
};
|
||||
|
||||
|
||||
@ -1428,12 +1428,14 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||
accountOwnerId: Schema.Types.ObjectId,
|
||||
|
||||
// SNS account cheats
|
||||
skipAllDialogue: Boolean,
|
||||
dontSubtractPurchaseCreditCost: Boolean,
|
||||
dontSubtractPurchasePlatinumCost: Boolean,
|
||||
dontSubtractPurchaseItemCost: Boolean,
|
||||
dontSubtractPurchaseStandingCost: Boolean,
|
||||
dontSubtractVoidTraces: Boolean,
|
||||
dontSubtractConsumables: Boolean,
|
||||
finishInvasionsInOneMission: Boolean,
|
||||
infiniteCredits: Boolean,
|
||||
infinitePlatinum: Boolean,
|
||||
infiniteEndo: Boolean,
|
||||
@ -1455,6 +1457,27 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||
claimingBlueprintRefundsIngredients: Boolean,
|
||||
instantResourceExtractorDrones: Boolean,
|
||||
noResourceExtractorDronesDamage: Boolean,
|
||||
missionsCanGiveAllRelics: Boolean,
|
||||
exceptionalRelicsAlwaysGiveBronzeReward: Boolean,
|
||||
flawlessRelicsAlwaysGiveSilverReward: Boolean,
|
||||
radiantRelicsAlwaysGiveGoldReward: Boolean,
|
||||
disableDailyTribute: Boolean,
|
||||
gainNoNegativeSyndicateStanding: Boolean,
|
||||
nemesisAlwaysCorrect: Boolean,
|
||||
nemesisHenchmenKillsMulptiplierGrineer: Number,
|
||||
nemesisHenchmenKillsMulptiplierCorpus: Number,
|
||||
nemesisAntivirusGainMultiplier: Number,
|
||||
nemesisHintProgressMultiplierGrineer: Number,
|
||||
nemesisHintProgressMultiplierCorpus: Number,
|
||||
nemesisWeaponFusionMultiplier: Number,
|
||||
nemesisExtraWeapon: Number,
|
||||
extraMissionRewards: Number,
|
||||
playerSkillGainsMultiplierSpace: Number,
|
||||
playerSkillGainsMultiplierDrifter: Number,
|
||||
extraRelicRewards: Number,
|
||||
relicPlatinumCommon: Number,
|
||||
relicPlatinumUncommon: Number,
|
||||
relicPlatinumRare: Number,
|
||||
|
||||
SubscribedToEmails: { type: Number, default: 0 },
|
||||
SubscribedToEmailsPersonalized: { type: Number, default: 0 },
|
||||
@ -1564,6 +1587,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
||||
OperatorLoadOuts: [operatorConfigSchema],
|
||||
//Drifter
|
||||
AdultOperatorLoadOuts: [operatorConfigSchema],
|
||||
OperatorCustomizationSlotPurchases: Number,
|
||||
// Kahl
|
||||
KahlLoadOuts: [operatorConfigSchema],
|
||||
|
||||
|
||||
@ -162,6 +162,7 @@ import { updateQuestController } from "../controllers/api/updateQuestController.
|
||||
import { updateSessionGetController, updateSessionPostController } from "../controllers/api/updateSessionController.ts";
|
||||
import { updateSongChallengeController } from "../controllers/api/updateSongChallengeController.ts";
|
||||
import { updateThemeController } from "../controllers/api/updateThemeController.ts";
|
||||
import { upgradeOperatorController } from "../controllers/api/upgradeOperatorController.ts";
|
||||
import { upgradesController } from "../controllers/api/upgradesController.ts";
|
||||
import { valenceSwapController } from "../controllers/api/valenceSwapController.ts";
|
||||
import { wishlistController } from "../controllers/api/wishlistController.ts";
|
||||
@ -229,6 +230,7 @@ apiRouter.get("/startLibraryPersonalTarget.php", startLibraryPersonalTargetContr
|
||||
apiRouter.get("/surveys.php", surveysController);
|
||||
apiRouter.get("/trading.php", tradingController);
|
||||
apiRouter.get("/updateSession.php", updateSessionGetController);
|
||||
apiRouter.get("/upgradeOperator.php", upgradeOperatorController);
|
||||
|
||||
// post
|
||||
apiRouter.post("/abortDojoComponent.php", abortDojoComponentController);
|
||||
|
||||
@ -14,6 +14,8 @@ import { addMissingMaxRankModsController } from "../controllers/custom/addMissin
|
||||
import { webuiFileChangeDetectedController } from "../controllers/custom/webuiFileChangeDetectedController.ts";
|
||||
import { completeAllMissionsController } from "../controllers/custom/completeAllMissionsController.ts";
|
||||
import { addMissingHelminthBlueprintsController } from "../controllers/custom/addMissingHelminthBlueprintsController.ts";
|
||||
import { unlockAllProfitTakerStagesController } from "../controllers/custom/unlockAllProfitTakerStagesController.ts";
|
||||
import { unlockAllSimarisResearchEntriesController } from "../controllers/custom/unlockAllSimarisResearchEntriesController.ts";
|
||||
|
||||
import { abilityOverrideController } from "../controllers/custom/abilityOverrideController.ts";
|
||||
import { createAccountController } from "../controllers/custom/createAccountController.ts";
|
||||
@ -48,6 +50,8 @@ customRouter.get("/addMissingMaxRankMods", addMissingMaxRankModsController);
|
||||
customRouter.get("/webuiFileChangeDetected", webuiFileChangeDetectedController);
|
||||
customRouter.get("/completeAllMissions", completeAllMissionsController);
|
||||
customRouter.get("/addMissingHelminthBlueprints", addMissingHelminthBlueprintsController);
|
||||
customRouter.get("/unlockAllProfitTakerStages", unlockAllProfitTakerStagesController);
|
||||
customRouter.get("/unlockAllSimarisResearchEntries", unlockAllSimarisResearchEntriesController);
|
||||
|
||||
customRouter.post("/abilityOverride", abilityOverrideController);
|
||||
customRouter.post("/createAccount", createAccountController);
|
||||
|
||||
@ -4,7 +4,7 @@ import { repoDir } from "../helpers/pathHelper.ts";
|
||||
import { args } from "../helpers/commandLineArguments.ts";
|
||||
import { Inbox } from "../models/inboxModel.ts";
|
||||
|
||||
export interface IConfig extends IConfigRemovedOptions {
|
||||
export interface IConfig {
|
||||
mongodbUrl: string;
|
||||
logger: {
|
||||
files: boolean;
|
||||
@ -18,7 +18,6 @@ export interface IConfig extends IConfigRemovedOptions {
|
||||
administratorNames?: string[];
|
||||
autoCreateAccount?: boolean;
|
||||
skipTutorial?: boolean;
|
||||
skipAllDialogue?: boolean;
|
||||
unlockAllScans?: boolean;
|
||||
unlockAllShipFeatures?: boolean;
|
||||
unlockAllShipDecorations?: boolean;
|
||||
@ -27,9 +26,6 @@ export interface IConfig extends IConfigRemovedOptions {
|
||||
unlockAllCapturaScenes?: boolean;
|
||||
unlockAllDecoRecipes?: boolean;
|
||||
fullyStockedVendors?: boolean;
|
||||
baroAlwaysAvailable?: boolean;
|
||||
baroFullyStocked?: boolean;
|
||||
unlockAllProfitTakerStages?: boolean;
|
||||
skipClanKeyCrafting?: boolean;
|
||||
noDojoRoomBuildStage?: boolean;
|
||||
noDojoDecoBuildStage?: boolean;
|
||||
@ -37,12 +33,6 @@ export interface IConfig extends IConfigRemovedOptions {
|
||||
noDojoResearchCosts?: boolean;
|
||||
noDojoResearchTime?: boolean;
|
||||
fastClanAscension?: boolean;
|
||||
missionsCanGiveAllRelics?: boolean;
|
||||
exceptionalRelicsAlwaysGiveBronzeReward?: boolean;
|
||||
flawlessRelicsAlwaysGiveSilverReward?: boolean;
|
||||
radiantRelicsAlwaysGiveGoldReward?: boolean;
|
||||
unlockAllSimarisResearchEntries?: boolean;
|
||||
disableDailyTribute?: boolean;
|
||||
spoofMasteryRank?: number;
|
||||
relicRewardItemCountMultiplier?: number;
|
||||
nightwaveStandingMultiplier?: number;
|
||||
@ -57,6 +47,9 @@ export interface IConfig extends IConfigRemovedOptions {
|
||||
resourceBoost?: boolean;
|
||||
tennoLiveRelay?: boolean;
|
||||
baroTennoConRelay?: boolean;
|
||||
baroAlwaysAvailable?: boolean;
|
||||
baroFullyStocked?: boolean;
|
||||
varziaFullyStocked?: boolean;
|
||||
wolfHunt?: boolean;
|
||||
orphixVenom?: boolean;
|
||||
longShadow?: boolean;
|
||||
@ -83,10 +76,9 @@ export interface IConfig extends IConfigRemovedOptions {
|
||||
duviriOverride?: string;
|
||||
nightwaveOverride?: string;
|
||||
allTheFissures?: string;
|
||||
varziaOverride?: string;
|
||||
circuitGameModes?: string[];
|
||||
darvoStockMultiplier?: number;
|
||||
varziaOverride?: string;
|
||||
varziaFullyStocked?: boolean;
|
||||
};
|
||||
dev?: {
|
||||
keepVendorsExpired?: boolean;
|
||||
@ -94,6 +86,7 @@ export interface IConfig extends IConfigRemovedOptions {
|
||||
}
|
||||
|
||||
export const configRemovedOptionsKeys = [
|
||||
"skipAllDialogue",
|
||||
"infiniteCredits",
|
||||
"infinitePlatinum",
|
||||
"infiniteEndo",
|
||||
@ -110,6 +103,8 @@ export const configRemovedOptionsKeys = [
|
||||
"unlockDoubleCapacityPotatoesEverywhere",
|
||||
"unlockExilusEverywhere",
|
||||
"unlockArcanesEverywhere",
|
||||
"unlockAllProfitTakerStages",
|
||||
"unlockAllSimarisResearchEntries",
|
||||
"noDailyStandingLimits",
|
||||
"noDailyFocusLimit",
|
||||
"noArgonCrystalDecay",
|
||||
@ -120,12 +115,15 @@ export const configRemovedOptionsKeys = [
|
||||
"syndicateMissionsRepeatable",
|
||||
"instantFinishRivenChallenge",
|
||||
"instantResourceExtractorDrones",
|
||||
"noResourceExtractorDronesDamage"
|
||||
] as const;
|
||||
|
||||
type IConfigRemovedOptions = {
|
||||
[K in (typeof configRemovedOptionsKeys)[number]]?: boolean;
|
||||
};
|
||||
"noResourceExtractorDronesDamage",
|
||||
"baroAlwaysAvailable",
|
||||
"baroFullyStocked",
|
||||
"missionsCanGiveAllRelics",
|
||||
"exceptionalRelicsAlwaysGiveBronzeReward",
|
||||
"flawlessRelicsAlwaysGiveSilverReward",
|
||||
"radiantRelicsAlwaysGiveGoldReward",
|
||||
"disableDailyTribute"
|
||||
];
|
||||
|
||||
export const configPath = path.join(repoDir, args.configPath ?? "config.json");
|
||||
|
||||
|
||||
@ -1,6 +1,13 @@
|
||||
import chokidar from "chokidar";
|
||||
import { logger } from "../utils/logger.ts";
|
||||
import { config, configPath, configRemovedOptionsKeys, loadConfig, syncConfigWithDatabase } from "./configService.ts";
|
||||
import {
|
||||
config,
|
||||
configPath,
|
||||
configRemovedOptionsKeys,
|
||||
loadConfig,
|
||||
syncConfigWithDatabase,
|
||||
type IConfig
|
||||
} from "./configService.ts";
|
||||
import { saveConfig, shouldReloadConfig } from "./configWriterService.ts";
|
||||
import { getWebPorts, startWebServer, stopWebServer } from "./webService.ts";
|
||||
import { sendWsBroadcast } from "./wsService.ts";
|
||||
@ -35,9 +42,11 @@ chokidar.watch(configPath).on("change", () => {
|
||||
export const validateConfig = (): void => {
|
||||
let modified = false;
|
||||
for (const key of configRemovedOptionsKeys) {
|
||||
if (config[key] !== undefined) {
|
||||
logger.debug(`Spotted removed option ${key} with value ${config[key]} in config.json.`);
|
||||
delete config[key];
|
||||
if (config[key as keyof IConfig] !== undefined) {
|
||||
logger.debug(
|
||||
`Spotted removed option ${key} with value ${String(config[key as keyof IConfig])} in config.json.`
|
||||
);
|
||||
delete config[key as keyof IConfig];
|
||||
modified = true;
|
||||
}
|
||||
}
|
||||
|
||||
@ -36,7 +36,7 @@ export const createNewEventMessages = async (req: Request): Promise<void> => {
|
||||
// Baro
|
||||
const baroIndex = Math.trunc((Date.now() - 910800000) / (unixTimesInMs.day * 14));
|
||||
const baroStart = baroIndex * (unixTimesInMs.day * 14) + 910800000;
|
||||
const baroActualStart = baroStart + unixTimesInMs.day * (config.baroAlwaysAvailable ? 0 : 12);
|
||||
const baroActualStart = baroStart + unixTimesInMs.day * (config.worldState?.baroAlwaysAvailable ? 0 : 12);
|
||||
if (Date.now() >= baroActualStart && account.LatestEventMessageDate.getTime() < baroActualStart) {
|
||||
newEventMessages.push({
|
||||
sndr: "/Lotus/Language/G1Quests/VoidTraderName",
|
||||
|
||||
@ -689,6 +689,7 @@ export const addItem = async (
|
||||
// Path-based duck typing
|
||||
switch (typeName.substr(1).split("/")[1]) {
|
||||
case "Powersuits":
|
||||
if (typeName.endsWith("AugmentCard")) break;
|
||||
switch (typeName.substr(1).split("/")[2]) {
|
||||
default: {
|
||||
return {
|
||||
@ -773,6 +774,10 @@ export const addItem = async (
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case "Skins": {
|
||||
return addSkin(inventory, typeName);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -869,6 +874,26 @@ export const addItem = async (
|
||||
break;
|
||||
}
|
||||
break;
|
||||
case "Weapons": {
|
||||
if (typeName.substr(1).split("/")[4] == "MeleeTrees") break;
|
||||
const productCategory = typeName.substr(1).split("/")[3];
|
||||
switch (productCategory) {
|
||||
case "Pistols":
|
||||
case "LongGuns":
|
||||
case "Melee": {
|
||||
const inventoryChanges = addEquipment(inventory, productCategory, typeName);
|
||||
return {
|
||||
...inventoryChanges,
|
||||
...occupySlot(
|
||||
inventory,
|
||||
productCategoryToInventoryBin(productCategory) ?? InventorySlot.WEAPONS,
|
||||
premiumPurchase
|
||||
)
|
||||
};
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
throw new Error(`unable to add item: ${typeName}`);
|
||||
};
|
||||
@ -1321,6 +1346,10 @@ export const addStanding = (
|
||||
let syndicate = inventory.Affiliations.find(x => x.Tag == syndicateTag);
|
||||
const syndicateMeta = ExportSyndicates[syndicateTag];
|
||||
|
||||
if (inventory.gainNoNegativeSyndicateStanding) {
|
||||
gainedStanding = Math.max(gainedStanding, 0);
|
||||
}
|
||||
|
||||
if (!syndicate) {
|
||||
syndicate =
|
||||
inventory.Affiliations[inventory.Affiliations.push({ Tag: syndicateTag, Standing: 0, Title: 0 }) - 1];
|
||||
|
||||
@ -201,10 +201,29 @@ export const addMissionInventoryUpdates = async (
|
||||
inventory.NemesisAbandonedRewards = inventoryUpdates.RewardInfo.NemesisAbandonedRewards;
|
||||
}
|
||||
if (inventoryUpdates.RewardInfo.NemesisHenchmenKills && inventory.Nemesis) {
|
||||
inventory.Nemesis.HenchmenKilled += inventoryUpdates.RewardInfo.NemesisHenchmenKills;
|
||||
let HenchmenKilledMultiplier = 1;
|
||||
switch (inventory.Nemesis.Faction) {
|
||||
case "FC_GRINEER":
|
||||
HenchmenKilledMultiplier = inventory.nemesisHenchmenKillsMulptiplierGrineer ?? 1;
|
||||
break;
|
||||
case "FC_CORPUS":
|
||||
HenchmenKilledMultiplier = inventory.nemesisHenchmenKillsMulptiplierCorpus ?? 1;
|
||||
break;
|
||||
}
|
||||
inventory.Nemesis.HenchmenKilled +=
|
||||
inventoryUpdates.RewardInfo.NemesisHenchmenKills * HenchmenKilledMultiplier;
|
||||
}
|
||||
if (inventoryUpdates.RewardInfo.NemesisHintProgress && inventory.Nemesis) {
|
||||
inventory.Nemesis.HintProgress += inventoryUpdates.RewardInfo.NemesisHintProgress;
|
||||
let HintProgressMultiplier = 1;
|
||||
switch (inventory.Nemesis.Faction) {
|
||||
case "FC_GRINEER":
|
||||
HintProgressMultiplier = inventory.nemesisHintProgressMultiplierGrineer ?? 1;
|
||||
break;
|
||||
case "FC_CORPUS":
|
||||
HintProgressMultiplier = inventory.nemesisHintProgressMultiplierCorpus ?? 1;
|
||||
break;
|
||||
}
|
||||
inventory.Nemesis.HintProgress += inventoryUpdates.RewardInfo.NemesisHintProgress * HintProgressMultiplier;
|
||||
if (inventory.Nemesis.Faction != "FC_INFESTATION" && inventory.Nemesis.Hints.length != 3) {
|
||||
const progressNeeded = [35, 60, 100][inventory.Nemesis.Hints.length];
|
||||
if (inventory.Nemesis.HintProgress >= progressNeeded) {
|
||||
@ -347,8 +366,10 @@ export const addMissionInventoryUpdates = async (
|
||||
break;
|
||||
}
|
||||
case "PlayerSkillGains": {
|
||||
inventory.PlayerSkills.LPP_SPACE += value.LPP_SPACE ?? 0;
|
||||
inventory.PlayerSkills.LPP_DRIFTER += value.LPP_DRIFTER ?? 0;
|
||||
inventory.PlayerSkills.LPP_SPACE +=
|
||||
(value.LPP_SPACE ?? 0) * (inventory.playerSkillGainsMultiplierSpace ?? 1);
|
||||
inventory.PlayerSkills.LPP_DRIFTER +=
|
||||
(value.LPP_DRIFTER ?? 0) * (inventory.playerSkillGainsMultiplierDrifter ?? 1);
|
||||
break;
|
||||
}
|
||||
case "CustomMarkers": {
|
||||
@ -775,6 +796,11 @@ export const addMissionInventoryUpdates = async (
|
||||
}
|
||||
case "InvasionProgress": {
|
||||
for (const clientProgress of value) {
|
||||
if (inventory.finishInvasionsInOneMission) {
|
||||
clientProgress.Delta *= 3;
|
||||
clientProgress.AttackerScore *= 3;
|
||||
clientProgress.DefenderScore *= 3;
|
||||
}
|
||||
const dbProgress = inventory.QualifyingInvasions.find(x =>
|
||||
x.invasionId.equals(clientProgress._id.$oid)
|
||||
);
|
||||
@ -838,6 +864,8 @@ export const addMissionInventoryUpdates = async (
|
||||
const att: string[] = [];
|
||||
let countedAtt: ITypeCount[] | undefined;
|
||||
|
||||
const extraWeaponCheat = inventory.nemesisExtraWeapon ?? 0; // 0 means no extra weapon and token
|
||||
|
||||
if (value.killed) {
|
||||
if (
|
||||
value.weaponLoc &&
|
||||
@ -847,6 +875,20 @@ export const addMissionInventoryUpdates = async (
|
||||
giveNemesisWeaponRecipe(inventory, weaponType, value.nemesisName, value.weaponLoc, profile);
|
||||
att.push(weaponType);
|
||||
}
|
||||
if (extraWeaponCheat >= 1) {
|
||||
for (let i = 0; i < extraWeaponCheat; i++) {
|
||||
const randomIndex = Math.floor(Math.random() * manifest.weapons.length);
|
||||
const randomWeapon = manifest.weapons[randomIndex];
|
||||
giveNemesisWeaponRecipe(
|
||||
inventory,
|
||||
randomWeapon,
|
||||
value.nemesisName,
|
||||
value.weaponLoc,
|
||||
profile
|
||||
);
|
||||
att.push(randomWeapon);
|
||||
}
|
||||
}
|
||||
//if (value.petLoc) {
|
||||
if (profile.petHead) {
|
||||
giveNemesisPetRecipe(inventory, value.nemesisName, profile);
|
||||
@ -889,7 +931,7 @@ export const addMissionInventoryUpdates = async (
|
||||
countedAtt = [
|
||||
{
|
||||
ItemType: "/Lotus/Types/Items/MiscItems/CodaWeaponBucks",
|
||||
ItemCount: getKillTokenRewardCount(inventory.Nemesis.fp)
|
||||
ItemCount: getKillTokenRewardCount(inventory.Nemesis.fp) * (extraWeaponCheat + 1)
|
||||
}
|
||||
];
|
||||
addMiscItems(inventory, countedAtt);
|
||||
@ -1323,6 +1365,21 @@ export const addMissionRewards = async (
|
||||
) {
|
||||
const reward = await crackRelic(inventory, voidTearWave.Participants[0], inventoryChanges);
|
||||
MissionRewards.push({ StoreItem: reward.type, ItemCount: reward.itemCount });
|
||||
|
||||
if ((inventory.extraRelicRewards ?? 0) >= 1) {
|
||||
for (let i = 0; i != inventory.extraRelicRewards; ++i) {
|
||||
//give a relic that will be removed later in crackRelic()
|
||||
const miscItemChanges = [
|
||||
{
|
||||
ItemType: voidTearWave.Participants[0].VoidProjection,
|
||||
ItemCount: 1
|
||||
}
|
||||
];
|
||||
addMiscItems(inventory, miscItemChanges);
|
||||
const reward = await crackRelic(inventory, voidTearWave.Participants[0], inventoryChanges);
|
||||
MissionRewards.push({ StoreItem: reward.type, ItemCount: reward.itemCount });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (strippedItems) {
|
||||
@ -1417,9 +1474,14 @@ export const addMissionRewards = async (
|
||||
|
||||
if (inventory.Nemesis.Faction == "FC_INFESTATION") {
|
||||
inventory.Nemesis.MissionCount += 1;
|
||||
let antivirusGain = 5;
|
||||
antivirusGain *= inventory.nemesisAntivirusGainMultiplier ?? 1;
|
||||
inventory.Nemesis.HenchmenKilled = Math.min(inventory.Nemesis.HenchmenKilled + antivirusGain, 95); // 5 progress per mission until 95
|
||||
|
||||
inventoryChanges.Nemesis.MissionCount ??= 0;
|
||||
inventoryChanges.Nemesis.MissionCount += 1;
|
||||
inventoryChanges.Nemesis.HenchmenKilled ??= 0;
|
||||
inventoryChanges.Nemesis.HenchmenKilled = inventory.Nemesis.HenchmenKilled;
|
||||
}
|
||||
|
||||
inventoryChanges.Nemesis.InfNodes = inventory.Nemesis.InfNodes;
|
||||
@ -1473,7 +1535,7 @@ export const addMissionRewards = async (
|
||||
if (vault) {
|
||||
currentJob = vault;
|
||||
if (jobType.endsWith("VaultBounty")) {
|
||||
currentJob.xpAmounts = [currentJob.xpAmounts.reduce((partialSum, a) => partialSum + a, 0)];
|
||||
currentJob.xpAmounts[rewardInfo.JobTier!] = currentJob.xpAmounts.reduce((s, a) => s + a, 0);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -1490,15 +1552,22 @@ export const addMissionRewards = async (
|
||||
medallionAmount = Math.floor(endlessJob.xpAmounts[index] * (1 + 0.15000001 * excess));
|
||||
}
|
||||
}
|
||||
await addItem(inventory, "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonB", medallionAmount);
|
||||
MissionRewards.push({
|
||||
StoreItem: "/Lotus/StoreItems/Types/Items/Deimos/EntratiFragmentUncommonB",
|
||||
ItemCount: medallionAmount
|
||||
});
|
||||
SyndicateXPItemReward = medallionAmount;
|
||||
logger.debug(
|
||||
`Giving ${medallionAmount} medallions for the ${rewardInfo.JobStage} stage of the ${rewardInfo.JobTier} tier bounty`
|
||||
);
|
||||
if (typeof medallionAmount === "number" && !isNaN(medallionAmount)) {
|
||||
await addItem(inventory, "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonB", medallionAmount);
|
||||
MissionRewards.push({
|
||||
StoreItem: "/Lotus/StoreItems/Types/Items/Deimos/EntratiFragmentUncommonB",
|
||||
ItemCount: medallionAmount
|
||||
});
|
||||
SyndicateXPItemReward = medallionAmount;
|
||||
logger.debug(
|
||||
`Giving ${medallionAmount} medallions for the ${rewardInfo.JobStage} stage of the ${rewardInfo.JobTier} tier bounty`
|
||||
);
|
||||
} else {
|
||||
logger.warning(
|
||||
`${jobType} tried to give ${medallionAmount} medallions for the ${rewardInfo.JobStage} stage of the ${rewardInfo.JobTier} tier bounty`
|
||||
);
|
||||
logger.warning(`currentJob`, { currentJob: currentJob });
|
||||
}
|
||||
} else {
|
||||
const specialCase = [
|
||||
{ endings: ["Heists/HeistProfitTakerBountyOne"], stage: 2, amount: 1000 },
|
||||
@ -1829,6 +1898,10 @@ function getRandomMissionDrops(
|
||||
ItemCount: 10
|
||||
});
|
||||
}
|
||||
drops.push({
|
||||
StoreItem: "/Lotus/StoreItems/Types/Gameplay/Duviri/Resource/DuviriDragonDropItem",
|
||||
ItemCount: 10
|
||||
});
|
||||
rewardManifests = ["/Lotus/Types/Game/MissionDecks/DuviriEncounterRewards/DuviriMurmurFinalChestRewards"];
|
||||
} else if (RewardInfo.T == 19) {
|
||||
if (config.worldState?.eightClaw) {
|
||||
@ -1837,6 +1910,10 @@ function getRandomMissionDrops(
|
||||
ItemCount: 15
|
||||
});
|
||||
}
|
||||
drops.push({
|
||||
StoreItem: "/Lotus/StoreItems/Types/Gameplay/Duviri/Resource/DuviriDragonDropItem",
|
||||
ItemCount: 15
|
||||
});
|
||||
rewardManifests = [
|
||||
"/Lotus/Types/Game/MissionDecks/DuviriEncounterRewards/DuviriMurmurFinalSteelChestRewards"
|
||||
];
|
||||
@ -2194,7 +2271,7 @@ function getRandomMissionDrops(
|
||||
}
|
||||
}
|
||||
|
||||
if (config.missionsCanGiveAllRelics) {
|
||||
if (inventory.missionsCanGiveAllRelics) {
|
||||
for (const drop of drops) {
|
||||
const itemType = fromStoreItem(drop.StoreItem);
|
||||
if (itemType in ExportRelics) {
|
||||
|
||||
@ -2630,84 +2630,92 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
);
|
||||
}
|
||||
|
||||
const thermiaFracturesCycleDay = day % 32;
|
||||
const isThermiaFracturesActive = thermiaFracturesCycleDay < 14;
|
||||
// Thermia Fractures activates for 14 days, with alternating 4 and 3-day breaks
|
||||
const thermiaFracturesCycleDay = day % 35;
|
||||
const isThermiaFracturesActive =
|
||||
thermiaFracturesCycleDay < 14 || (thermiaFracturesCycleDay >= 18 && thermiaFracturesCycleDay < 32);
|
||||
const activeThermiaFracturesCycleDay =
|
||||
thermiaFracturesCycleDay - (thermiaFracturesCycleDay < 14 ? 0 : thermiaFracturesCycleDay < 18 ? 14 : 32);
|
||||
|
||||
if (config.worldState?.thermiaFracturesOverride ?? isThermiaFracturesActive) {
|
||||
const activeStartDay = day - thermiaFracturesCycleDay;
|
||||
const activeStartDay = day - activeThermiaFracturesCycleDay;
|
||||
|
||||
const count = config.worldState?.thermiaFracturesProgressOverride ?? 0;
|
||||
const activation = config.worldState?.thermiaFracturesOverride ? 1740416400000 : getSortieTime(activeStartDay);
|
||||
const expiry = config.worldState?.thermiaFracturesOverride ? 2000000000000 : getSortieTime(activeStartDay + 14);
|
||||
|
||||
worldState.Goals.push({
|
||||
_id: { $oid: "5c7cb0d00000000000000000" },
|
||||
Activation: { $date: { $numberLong: activation.toString() } },
|
||||
Expiry: { $date: { $numberLong: expiry.toString() } },
|
||||
Node: "SolNode129",
|
||||
ScoreVar: "FissuresClosed",
|
||||
ScoreLocTag: "/Lotus/Language/G1Quests/HeatFissuresEventScore",
|
||||
Count: count,
|
||||
HealthPct: count / 100,
|
||||
Regions: [1],
|
||||
Desc: "/Lotus/Language/G1Quests/HeatFissuresEventName",
|
||||
ToolTip: "/Lotus/Language/G1Quests/HeatFissuresEventDesc",
|
||||
OptionalInMission: true,
|
||||
Tag: "HeatFissure",
|
||||
UpgradeIds: [{ $oid: "5c81cefa4c4566791728eaa7" }, { $oid: "5c81cefa4c4566791728eaa6" }],
|
||||
Personal: true,
|
||||
Community: true,
|
||||
Goal: 100,
|
||||
Reward: {
|
||||
items: ["/Lotus/StoreItems/Weapons/Corpus/LongGuns/CrpBFG/Vandal/VandalCrpBFG"]
|
||||
},
|
||||
InterimGoals: [5, 25, 50, 75],
|
||||
InterimRewards: [
|
||||
{ items: ["/Lotus/StoreItems/Upgrades/Skins/Clan/OrbBadgeItem"] },
|
||||
{
|
||||
items: [
|
||||
"/Lotus/StoreItems/Upgrades/Mods/DualSource/Shotgun/ShotgunMedicMod",
|
||||
"/Lotus/StoreItems/Upgrades/Mods/DualSource/Rifle/SerratedRushMod"
|
||||
]
|
||||
},
|
||||
{
|
||||
items: [
|
||||
"/Lotus/StoreItems/Upgrades/Mods/DualSource/Pistol/MultishotDodgeMod",
|
||||
"/Lotus/StoreItems/Upgrades/Mods/DualSource/Melee/CritDamageChargeSpeedMod"
|
||||
]
|
||||
},
|
||||
{ items: ["/Lotus/StoreItems/Upgrades/Skins/Sigils/OrbSigil"] }
|
||||
]
|
||||
});
|
||||
worldState.NodeOverrides.push({
|
||||
_id: { $oid: "5c7cb0d00000000000000000" },
|
||||
Activation: { $date: { $numberLong: activation.toString() } },
|
||||
Expiry: { $date: { $numberLong: expiry.toString() } },
|
||||
Node: "SolNode129",
|
||||
Faction: "FC_CORPUS",
|
||||
CustomNpcEncounters: ["/Lotus/Types/Gameplay/Venus/Encounters/Heists/ExploiterHeistFissure"]
|
||||
});
|
||||
if (count >= 35) {
|
||||
worldState.GlobalUpgrades.push({
|
||||
_id: { $oid: "5c81cefa4c4566791728eaa6" },
|
||||
// If we push it, the game may show the event even tho it's not activated yet (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/2721)
|
||||
if (timeMs >= activation) {
|
||||
worldState.Goals.push({
|
||||
_id: { $oid: "5c7cb0d00000000000000000" },
|
||||
Activation: { $date: { $numberLong: activation.toString() } },
|
||||
ExpiryDate: { $date: { $numberLong: expiry.toString() } },
|
||||
UpgradeType: "GAMEPLAY_MONEY_REWARD_AMOUNT",
|
||||
OperationType: "MULTIPLY",
|
||||
Value: 2,
|
||||
Nodes: ["SolNode129"]
|
||||
Expiry: { $date: { $numberLong: expiry.toString() } },
|
||||
Node: "SolNode129",
|
||||
ScoreVar: "FissuresClosed",
|
||||
ScoreLocTag: "/Lotus/Language/G1Quests/HeatFissuresEventScore",
|
||||
Count: count,
|
||||
HealthPct: count / 100,
|
||||
Regions: [1],
|
||||
Desc: "/Lotus/Language/G1Quests/HeatFissuresEventName",
|
||||
ToolTip: "/Lotus/Language/G1Quests/HeatFissuresEventDesc",
|
||||
OptionalInMission: true,
|
||||
Tag: "HeatFissure",
|
||||
UpgradeIds: [{ $oid: "5c81cefa4c4566791728eaa7" }, { $oid: "5c81cefa4c4566791728eaa6" }],
|
||||
Personal: true,
|
||||
Community: true,
|
||||
Goal: 100,
|
||||
Reward: {
|
||||
items: ["/Lotus/StoreItems/Weapons/Corpus/LongGuns/CrpBFG/Vandal/VandalCrpBFG"]
|
||||
},
|
||||
InterimGoals: [5, 25, 50, 75],
|
||||
InterimRewards: [
|
||||
{ items: ["/Lotus/StoreItems/Upgrades/Skins/Clan/OrbBadgeItem"] },
|
||||
{
|
||||
items: [
|
||||
"/Lotus/StoreItems/Upgrades/Mods/DualSource/Shotgun/ShotgunMedicMod",
|
||||
"/Lotus/StoreItems/Upgrades/Mods/DualSource/Rifle/SerratedRushMod"
|
||||
]
|
||||
},
|
||||
{
|
||||
items: [
|
||||
"/Lotus/StoreItems/Upgrades/Mods/DualSource/Pistol/MultishotDodgeMod",
|
||||
"/Lotus/StoreItems/Upgrades/Mods/DualSource/Melee/CritDamageChargeSpeedMod"
|
||||
]
|
||||
},
|
||||
{ items: ["/Lotus/StoreItems/Upgrades/Skins/Sigils/OrbSigil"] }
|
||||
]
|
||||
});
|
||||
}
|
||||
// Not sure about that
|
||||
if (count == 100) {
|
||||
worldState.GlobalUpgrades.push({
|
||||
_id: { $oid: "5c81cefa4c4566791728eaa7" },
|
||||
worldState.NodeOverrides.push({
|
||||
_id: { $oid: "5c7cb0d00000000000000000" },
|
||||
Activation: { $date: { $numberLong: activation.toString() } },
|
||||
ExpiryDate: { $date: { $numberLong: expiry.toString() } },
|
||||
UpgradeType: "GAMEPLAY_PICKUP_AMOUNT",
|
||||
OperationType: "MULTIPLY",
|
||||
Value: 2,
|
||||
Nodes: ["SolNode129"]
|
||||
Expiry: { $date: { $numberLong: expiry.toString() } },
|
||||
Node: "SolNode129",
|
||||
Faction: "FC_CORPUS",
|
||||
CustomNpcEncounters: ["/Lotus/Types/Gameplay/Venus/Encounters/Heists/ExploiterHeistFissure"]
|
||||
});
|
||||
if (count >= 35) {
|
||||
worldState.GlobalUpgrades.push({
|
||||
_id: { $oid: "5c81cefa4c4566791728eaa6" },
|
||||
Activation: { $date: { $numberLong: activation.toString() } },
|
||||
ExpiryDate: { $date: { $numberLong: expiry.toString() } },
|
||||
UpgradeType: "GAMEPLAY_MONEY_REWARD_AMOUNT",
|
||||
OperationType: "MULTIPLY",
|
||||
Value: 2,
|
||||
Nodes: ["SolNode129"]
|
||||
});
|
||||
}
|
||||
// Not sure about that
|
||||
if (count == 100) {
|
||||
worldState.GlobalUpgrades.push({
|
||||
_id: { $oid: "5c81cefa4c4566791728eaa7" },
|
||||
Activation: { $date: { $numberLong: activation.toString() } },
|
||||
ExpiryDate: { $date: { $numberLong: expiry.toString() } },
|
||||
UpgradeType: "GAMEPLAY_PICKUP_AMOUNT",
|
||||
OperationType: "MULTIPLY",
|
||||
Value: 2,
|
||||
Nodes: ["SolNode129"]
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -2933,7 +2941,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
{
|
||||
const baroIndex = Math.trunc((Date.now() - 910800000) / (unixTimesInMs.day * 14));
|
||||
const baroStart = baroIndex * (unixTimesInMs.day * 14) + 910800000;
|
||||
const baroActualStart = baroStart + unixTimesInMs.day * (config.baroAlwaysAvailable ? 0 : 12);
|
||||
const baroActualStart = baroStart + unixTimesInMs.day * (config.worldState?.baroAlwaysAvailable ? 0 : 12);
|
||||
const baroEnd = baroStart + unixTimesInMs.day * 14;
|
||||
const baroNode = ["EarthHUB", "MercuryHUB", "SaturnHUB", "PlutoHUB"][baroIndex % 4];
|
||||
const vt: IVoidTrader = {
|
||||
@ -2946,7 +2954,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
};
|
||||
worldState.VoidTraders.push(vt);
|
||||
if (isBeforeNextExpectedWorldStateRefresh(timeMs, baroActualStart)) {
|
||||
if (config.baroFullyStocked) {
|
||||
if (config.worldState?.baroFullyStocked) {
|
||||
fullyStockBaro(vt);
|
||||
} else {
|
||||
const rng = new SRng(new SRng(baroIndex).randomInt(0, 100_000));
|
||||
|
||||
@ -21,12 +21,14 @@ export type InventoryDatabaseEquipment = {
|
||||
|
||||
// Fields specific to SNS
|
||||
export interface IAccountCheats {
|
||||
skipAllDialogue?: boolean;
|
||||
dontSubtractPurchaseCreditCost?: boolean;
|
||||
dontSubtractPurchasePlatinumCost?: boolean;
|
||||
dontSubtractPurchaseItemCost?: boolean;
|
||||
dontSubtractPurchaseStandingCost?: boolean;
|
||||
dontSubtractVoidTraces?: boolean;
|
||||
dontSubtractConsumables?: boolean;
|
||||
finishInvasionsInOneMission?: boolean;
|
||||
infiniteCredits?: boolean;
|
||||
infinitePlatinum?: boolean;
|
||||
infiniteEndo?: boolean;
|
||||
@ -48,6 +50,28 @@ export interface IAccountCheats {
|
||||
claimingBlueprintRefundsIngredients?: boolean;
|
||||
instantResourceExtractorDrones?: boolean;
|
||||
noResourceExtractorDronesDamage?: boolean;
|
||||
missionsCanGiveAllRelics?: boolean;
|
||||
exceptionalRelicsAlwaysGiveBronzeReward?: boolean;
|
||||
flawlessRelicsAlwaysGiveSilverReward?: boolean;
|
||||
radiantRelicsAlwaysGiveGoldReward?: boolean;
|
||||
disableDailyTribute?: boolean;
|
||||
gainNoNegativeSyndicateStanding?: boolean;
|
||||
nemesisAlwaysCorrect?: boolean;
|
||||
nemesisHenchmenKillsMulptiplierGrineer?: number;
|
||||
nemesisHenchmenKillsMulptiplierCorpus?: number;
|
||||
nemesisAntivirusGainMultiplier?: number;
|
||||
nemesisHintProgressMultiplierGrineer?: number;
|
||||
nemesisHintProgressMultiplierCorpus?: number;
|
||||
nemesisWeaponFusionMultiplier?: number;
|
||||
nemesisExtraWeapon?: number;
|
||||
extraMissionRewards?: number;
|
||||
playerSkillGainsMultiplierSpace?: number;
|
||||
playerSkillGainsMultiplierDrifter?: number;
|
||||
extraRelicRewards?: number;
|
||||
crackRelicForPlatinum?: boolean;
|
||||
relicPlatinumCommon?: number;
|
||||
relicPlatinumUncommon?: number;
|
||||
relicPlatinumRare?: number;
|
||||
}
|
||||
|
||||
export interface IInventoryDatabase
|
||||
@ -374,6 +398,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
||||
CrewMembers: ICrewMemberClient[];
|
||||
LotusCustomization?: ILotusCustomization;
|
||||
UseAdultOperatorLoadout?: boolean;
|
||||
OperatorCustomizationSlotPurchases?: number;
|
||||
NemesisAbandonedRewards: string[];
|
||||
LastInventorySync?: IOid;
|
||||
NextRefill?: IMongoDate;
|
||||
|
||||
@ -92,12 +92,36 @@
|
||||
<div data-route="/webui/inventory" data-title="Inventory | OpenWF WebUI">
|
||||
<p class="mb-3" data-loc="general_inventoryUpdateNote"></p>
|
||||
<div class="card mb-3">
|
||||
<h5 class="card-header" data-loc="inventory_addItems"></h5>
|
||||
<form class="card-body input-group" onsubmit="doAcquireMiscItems();return false;">
|
||||
<input class="form-control" id="miscitem-count" type="number" value="1" />
|
||||
<input class="form-control w-50" id="miscitem-type" list="datalist-miscitems" />
|
||||
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||
</form>
|
||||
<div class="card-header">
|
||||
<ul class="nav nav-tabs card-header-tabs">
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" id="miscItems-tab" data-bs-toggle="tab" data-bs-target="#miscItems-tab-content" data-loc="inventory_addItems"></button>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<button class="nav-link" id="typeName-tab" data-bs-toggle="tab" data-bs-target="#typeName-tab-content" data-loc="inventory_addItemByItemType"></button>
|
||||
</li>
|
||||
</ul>
|
||||
</div>
|
||||
<div class="card-body">
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane" id="miscItems-tab-content">
|
||||
<form class="card-body input-group" onsubmit="doAcquireMiscItems();return false;">
|
||||
<input class="form-control" id="miscitem-count" type="number" value="1" />
|
||||
<input class="form-control w-50" id="miscitem-type" list="datalist-miscitems" />
|
||||
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||
</form>
|
||||
</div>
|
||||
<div class="tab-pane" id="typeName-tab-content">
|
||||
<form class="card-body" onsubmit="addItemByItemType();return false;">
|
||||
<p data-loc="inventory_addItemByItemType_warning"></p>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="typeName-type" />
|
||||
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row g-3 mb-3">
|
||||
<div class="col-md-3">
|
||||
@ -647,6 +671,10 @@
|
||||
<div class="card">
|
||||
<h5 class="card-header" data-loc="cheats_account"></h5>
|
||||
<div class="card-body" id="account-cheats">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="skipAllDialogue" />
|
||||
<label class="form-check-label" for="skipAllDialogue" data-loc="cheats_skipAllDialogue"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="dontSubtractPurchaseCreditCost" />
|
||||
<label class="form-check-label" for="dontSubtractPurchaseCreditCost" data-loc="cheats_dontSubtractPurchaseCreditCost"></label>
|
||||
@ -755,14 +783,150 @@
|
||||
<input class="form-check-input" type="checkbox" id="claimingBlueprintRefundsIngredients" />
|
||||
<label class="form-check-label" for="claimingBlueprintRefundsIngredients" data-loc="cheats_claimingBlueprintRefundsIngredients"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="missionsCanGiveAllRelics" />
|
||||
<label class="form-check-label" for="missionsCanGiveAllRelics" data-loc="cheats_missionsCanGiveAllRelics"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="exceptionalRelicsAlwaysGiveBronzeReward" />
|
||||
<label class="form-check-label" for="exceptionalRelicsAlwaysGiveBronzeReward" data-loc="cheats_exceptionalRelicsAlwaysGiveBronzeReward"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="flawlessRelicsAlwaysGiveSilverReward" />
|
||||
<label class="form-check-label" for="flawlessRelicsAlwaysGiveSilverReward" data-loc="cheats_flawlessRelicsAlwaysGiveSilverReward"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="radiantRelicsAlwaysGiveGoldReward" />
|
||||
<label class="form-check-label" for="radiantRelicsAlwaysGiveGoldReward" data-loc="cheats_radiantRelicsAlwaysGiveGoldReward"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="disableDailyTribute" />
|
||||
<label class="form-check-label" for="disableDailyTribute" data-loc="cheats_disableDailyTribute"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="finishInvasionsInOneMission" />
|
||||
<label class="form-check-label" for="finishInvasionsInOneMission" data-loc="cheats_finishInvasionsInOneMission"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="gainNoNegativeSyndicateStanding" />
|
||||
<label class="form-check-label" for="gainNoNegativeSyndicateStanding" data-loc="cheats_gainNoNegativeSyndicateStanding"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="nemesisAlwaysCorrect" />
|
||||
<label class="form-check-label" for="nemesisAlwaysCorrect" data-loc="cheats_nemesisAlwaysCorrect"></label>
|
||||
</div>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="nemesisHenchmenKillsMultiplierGrineer" data-loc="cheats_nemesisHenchmenKillsMultiplierGrineer"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="nemesisHenchmenKillsMultiplierGrineer" type="number" min="-1" max="65535" data-default="1" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="nemesisHenchmenKillsMultiplierCorpus" data-loc="cheats_nemesisHenchmenKillsMultiplierCorpus"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="nemesisHenchmenKillsMultiplierCorpus" type="number" min="-1" max="65535" data-default="1" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="nemesisAntivirusGainMultiplier" data-loc="cheats_nemesisAntivirusGainMultiplier"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="nemesisAntivirusGainMultiplier" type="number" min="-1" max="65535" data-default="1" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="nemesisHintProgressMultiplierGrineer" data-loc="cheats_nemesisHintProgressMultiplierGrineer"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="nemesisHintProgressMultiplierGrineer" type="number" min="-1" max="65535" data-default="1" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="nemesisHintProgressMultiplierCorpus" data-loc="cheats_nemesisHintProgressMultiplierCorpus"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="nemesisHintProgressMultiplierCorpus" type="number" min="-1" max="65535" data-default="1" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="nemesisWeaponFusionMultiplier" data-loc="cheats_nemesisWeaponFusionMultiplier"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="nemesisWeaponFusionMultiplier" type="number" min="1" max="65535" data-default="1" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="nemesisExtraWeapon" data-loc="cheats_nemesisExtraWeapon"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="nemesisExtraWeapon" type="number" min="0" max="65535" data-default="0" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="extraMissionRewards" data-loc="cheats_extraMissionRewards"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="extraMissionRewards" type="number" min="0" max="65535" data-default="0" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="playerSkillGainsMultiplierSpace" data-loc="cheats_playerSkillGainsMultiplierSpace"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="playerSkillGainsMultiplierSpace" type="number" min="1" max="65535" data-default="1" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="playerSkillGainsMultiplierDrifter" data-loc="cheats_playerSkillGainsMultiplierDrifter"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="playerSkillGainsMultiplierDrifter" type="number" min="1" max="65535" data-default="1" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="extraRelicRewards" data-loc="cheats_extraRelicRewards"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="extraRelicRewards" type="number" min="0" max="65535" data-default="0" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="crackRelicForPlatinum" />
|
||||
<label class="form-check-label" for="crackRelicForPlatinum" data-loc="cheats_crackRelicForPlatinum"></label>
|
||||
</div>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="relicPlatinumCommon" data-loc="cheats_relicPlatinumCommon"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="relicPlatinumCommon" type="number" min="0" max="65535" data-default="2" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="relicPlatinumUncommon" data-loc="cheats_relicPlatinumUncommon"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="relicPlatinumUncommon" type="number" min="0" max="65535" data-default="5" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<form class="form-group mt-2">
|
||||
<label class="form-label" for="relicPlatinumRare" data-loc="cheats_relicPlatinumRare"></label>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="relicPlatinumRare" type="number" min="0" max="65535" data-default="12" />
|
||||
<button class="btn btn-secondary" type="button" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
<div class="mt-2 mb-2 d-flex flex-wrap gap-2">
|
||||
<button class="btn btn-primary" onclick="debounce(doUnlockAllMissions);" data-loc="cheats_unlockAllMissions"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(unlockAllMissions);" data-loc="cheats_unlockAllMissions"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(markAllAsRead);" data-loc="cheats_markAllAsRead"></button>
|
||||
<button class="btn btn-primary" onclick="doUnlockAllFocusSchools();" data-loc="cheats_unlockAllFocusSchools"></button>
|
||||
<button class="btn btn-primary" onclick="doHelminthUnlockAll();" data-loc="cheats_helminthUnlockAll"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(addMissingHelminthRecipes);" data-loc="cheats_addMissingSubsumedAbilities"></button>
|
||||
<button class="btn btn-primary" onclick="doIntrinsicsUnlockAll();" data-loc="cheats_intrinsicsUnlockAll"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(doMaxPlexus);" data-loc="inventory_maxPlexus"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(unlockAllProfitTakerStages);" data-loc="cheats_unlockAllProfitTakerStages"></button>
|
||||
<button class="btn btn-primary" onclick="debounce(unlockAllSimarisResearchEntries);" data-loc="cheats_unlockAllSimarisResearchEntries"></button>
|
||||
</div>
|
||||
<form class="mt-2" onsubmit="doChangeSupportedSyndicate(); return false;">
|
||||
<label class="form-label" for="changeSyndicate" data-loc="cheats_changeSupportedSyndicate"></label>
|
||||
@ -786,10 +950,6 @@
|
||||
<input class="form-check-input" type="checkbox" id="skipTutorial" />
|
||||
<label class="form-check-label" for="skipTutorial" data-loc="cheats_skipTutorial"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="skipAllDialogue" />
|
||||
<label class="form-check-label" for="skipAllDialogue" data-loc="cheats_skipAllDialogue"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="unlockAllScans" />
|
||||
<label class="form-check-label" for="unlockAllScans" data-loc="cheats_unlockAllScans"></label>
|
||||
@ -822,18 +982,6 @@
|
||||
<input class="form-check-input" type="checkbox" id="fullyStockedVendors" />
|
||||
<label class="form-check-label" for="fullyStockedVendors" data-loc="cheats_fullyStockedVendors"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="baroAlwaysAvailable" />
|
||||
<label class="form-check-label" for="baroAlwaysAvailable" data-loc="cheats_baroAlwaysAvailable"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="baroFullyStocked" />
|
||||
<label class="form-check-label" for="baroFullyStocked" data-loc="cheats_baroFullyStocked"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="unlockAllProfitTakerStages" />
|
||||
<label class="form-check-label" for="unlockAllProfitTakerStages" data-loc="cheats_unlockAllProfitTakerStages"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="skipClanKeyCrafting" />
|
||||
<label class="form-check-label" for="skipClanKeyCrafting" data-loc="cheats_skipClanKeyCrafting"></label>
|
||||
@ -862,30 +1010,6 @@
|
||||
<input class="form-check-input" type="checkbox" id="fastClanAscension" />
|
||||
<label class="form-check-label" for="fastClanAscension" data-loc="cheats_fastClanAscension"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="missionsCanGiveAllRelics" />
|
||||
<label class="form-check-label" for="missionsCanGiveAllRelics" data-loc="cheats_missionsCanGiveAllRelics"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="exceptionalRelicsAlwaysGiveBronzeReward" />
|
||||
<label class="form-check-label" for="exceptionalRelicsAlwaysGiveBronzeReward" data-loc="cheats_exceptionalRelicsAlwaysGiveBronzeReward"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="flawlessRelicsAlwaysGiveSilverReward" />
|
||||
<label class="form-check-label" for="flawlessRelicsAlwaysGiveSilverReward" data-loc="cheats_flawlessRelicsAlwaysGiveSilverReward"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="radiantRelicsAlwaysGiveGoldReward" />
|
||||
<label class="form-check-label" for="radiantRelicsAlwaysGiveGoldReward" data-loc="cheats_radiantRelicsAlwaysGiveGoldReward"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="unlockAllSimarisResearchEntries" />
|
||||
<label class="form-check-label" for="unlockAllSimarisResearchEntries" data-loc="cheats_unlockAllSimarisResearchEntries"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="disableDailyTribute" />
|
||||
<label class="form-check-label" for="disableDailyTribute" data-loc="cheats_disableDailyTribute"></label>
|
||||
</div>
|
||||
<form class="form-group mt-2" onsubmit="doSaveConfigInt('spoofMasteryRank'); return false;">
|
||||
<label class="form-label" for="spoofMasteryRank" data-loc="cheats_spoofMasteryRank"></label>
|
||||
<div class="input-group">
|
||||
@ -933,6 +1057,14 @@
|
||||
<input class="form-check-input" type="checkbox" id="worldState.baroTennoConRelay" />
|
||||
<label class="form-check-label" for="worldState.baroTennoConRelay" data-loc="worldState_baroTennoConRelay"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="worldState.baroAlwaysAvailable" />
|
||||
<label class="form-check-label" for="worldState.baroAlwaysAvailable" data-loc="cheats_baroAlwaysAvailable"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="worldState.baroFullyStocked" />
|
||||
<label class="form-check-label" for="worldState.baroFullyStocked" data-loc="cheats_baroFullyStocked"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="worldState.varziaFullyStocked" />
|
||||
<label class="form-check-label" for="worldState.varziaFullyStocked" data-loc="worldState_varziaFullyStocked"></label>
|
||||
|
||||
@ -649,6 +649,14 @@ function updateInventory() {
|
||||
];
|
||||
|
||||
// Populate inventory route
|
||||
|
||||
document.getElementById("typeName-tab").classList.remove("active");
|
||||
document.getElementById("typeName-tab-content").classList.remove("active", "show");
|
||||
document.getElementById("typeName-type").value = "";
|
||||
|
||||
document.getElementById("miscItems-tab").classList.add("active");
|
||||
document.getElementById("miscItems-tab-content").classList.add("active", "show");
|
||||
|
||||
["RegularCredits", "PremiumCredits", "FusionPoints", "PrimeTokens"].forEach(currency => {
|
||||
document.getElementById(currency + "-owned").textContent = loc("currency_owned")
|
||||
.split("|COUNT|")
|
||||
@ -1495,7 +1503,11 @@ function updateInventory() {
|
||||
});
|
||||
|
||||
for (const elm of accountCheats) {
|
||||
elm.checked = !!data[elm.id];
|
||||
if (elm.type === "checkbox") {
|
||||
elm.checked = !!data[elm.id];
|
||||
} else if (elm.type === "number") {
|
||||
elm.value = data[elm.id] !== undefined ? data[elm.id] : elm.getAttribute("data-default") || "";
|
||||
}
|
||||
}
|
||||
});
|
||||
});
|
||||
@ -1685,7 +1697,7 @@ function doAcquireEvolution() {
|
||||
setEvolutionProgress([{ ItemType: uniqueName, Rank: permanentEvolutionWeapons.has(uniqueName) ? 0 : 1 }]);
|
||||
}
|
||||
|
||||
$(document).on("input", "input[list]", function () {
|
||||
$(document).on("input", "input", function () {
|
||||
$(this).removeClass("is-invalid");
|
||||
});
|
||||
|
||||
@ -2008,6 +2020,35 @@ function doAcquireMiscItems() {
|
||||
}
|
||||
}
|
||||
|
||||
function addItemByItemType() {
|
||||
const ItemType = document.getElementById("typeName-type").value;
|
||||
// Must start with "/Lotus/", contain only A–Z letters, no "//", and not end with "/"
|
||||
if (!ItemType || !/^\/Lotus\/(?:[A-Za-z]+(?:\/[A-Za-z]+)*)$/.test(ItemType)) {
|
||||
$("#typeName-type").addClass("is-invalid").focus();
|
||||
return;
|
||||
}
|
||||
revalidateAuthz().then(() => {
|
||||
$.post({
|
||||
url: "/custom/addItems?" + window.authz,
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify([
|
||||
{
|
||||
ItemType,
|
||||
ItemCount: 1
|
||||
}
|
||||
])
|
||||
})
|
||||
.done(function (_, _, jqXHR) {
|
||||
if (jqXHR.status === 200) {
|
||||
updateInventory();
|
||||
}
|
||||
})
|
||||
.fail(function () {
|
||||
$("#typeName-type").addClass("is-invalid").focus();
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
function doAcquireRiven() {
|
||||
let fingerprint;
|
||||
try {
|
||||
@ -2330,15 +2371,16 @@ function doIntrinsicsUnlockAll() {
|
||||
});
|
||||
}
|
||||
|
||||
document.querySelectorAll("#account-cheats input[type=checkbox]").forEach(elm => {
|
||||
document.querySelectorAll("#account-cheats input[type=checkbox], #account-cheats input[type=number]").forEach(elm => {
|
||||
elm.onchange = function () {
|
||||
revalidateAuthz().then(() => {
|
||||
const value = elm.type === "checkbox" ? elm.checked : elm.value;
|
||||
$.post({
|
||||
url: "/custom/setAccountCheat?" + window.authz /*+ "&wsid=" + wsid*/,
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify({
|
||||
key: elm.id,
|
||||
value: elm.checked
|
||||
value: value
|
||||
})
|
||||
});
|
||||
});
|
||||
@ -2713,12 +2755,24 @@ async function doMaxPlexus() {
|
||||
}
|
||||
}
|
||||
|
||||
async function doUnlockAllMissions() {
|
||||
async function unlockAllMissions() {
|
||||
await revalidateAuthz();
|
||||
await fetch("/custom/completeAllMissions?" + window.authz);
|
||||
toast(loc("cheats_unlockAllMissions_ok"));
|
||||
}
|
||||
|
||||
async function unlockAllProfitTakerStages() {
|
||||
await revalidateAuthz();
|
||||
await fetch("/custom/unlockAllProfitTakerStages?" + window.authz);
|
||||
toast(loc("cheats_unlockSucc"));
|
||||
}
|
||||
|
||||
async function unlockAllSimarisResearchEntries() {
|
||||
await revalidateAuthz();
|
||||
await fetch("/custom/unlockAllSimarisResearchEntries?" + window.authz);
|
||||
toast(loc("cheats_unlockSucc"));
|
||||
}
|
||||
|
||||
const importSamples = {
|
||||
maxFocus: {
|
||||
FocusUpgrades: [
|
||||
|
||||
@ -79,6 +79,8 @@ dict = {
|
||||
navbar_cheats: `Cheats`,
|
||||
navbar_import: `Importieren`,
|
||||
inventory_addItems: `Gegenstände hinzufügen`,
|
||||
inventory_addItemByItemType: `[UNTRANSLATED] Raw`,
|
||||
inventory_addItemByItemType_warning: `[UNTRANSLATED] Use this feature at your own risk. It may break your inventory, and you will need to remove items manually if something goes wrong.`,
|
||||
inventory_suits: `Warframes`,
|
||||
inventory_longGuns: `Primärwaffen`,
|
||||
inventory_pistols: `Sekundärwaffen`,
|
||||
@ -210,6 +212,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Baro hat volles Inventar`,
|
||||
cheats_syndicateMissionsRepeatable: `Syndikat-Missionen wiederholbar`,
|
||||
cheats_unlockAllProfitTakerStages: `Alle Profiteintreiber-Phasen freischalten`,
|
||||
cheats_unlockSucc: `[UNTRANSLATED] Successfully unlocked.`,
|
||||
cheats_instantFinishRivenChallenge: `Riven-Mod Herausforderung sofort abschließen`,
|
||||
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
|
||||
cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,
|
||||
@ -238,6 +241,24 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `Unterstütztes Syndikat`,
|
||||
cheats_changeButton: `Ändern`,
|
||||
cheats_markAllAsRead: `Posteingang als gelesen markieren`,
|
||||
cheats_finishInvasionsInOneMission: `[UNTRANSLATED] Finish Invasions in One Mission`,
|
||||
cheats_gainNoNegativeSyndicateStanding: `[UNTRANSLATED] Gain No Negative Syndicate Standing`,
|
||||
cheats_nemesisAlwaysCorrect: `[UNTRANSLATED] Any Guess is Correct`,
|
||||
cheats_nemesisHenchmenKillsMultiplierGrineer: `[UNTRANSLATED] Rage Progess Multiplier (Grineer)`,
|
||||
cheats_nemesisHenchmenKillsMultiplierCorpus: `[UNTRANSLATED] Rage Progess Multiplier (Corpus)`,
|
||||
cheats_nemesisAntivirusGainMultiplier: `[UNTRANSLATED] Antivirus Progress Multiplier`,
|
||||
cheats_nemesisHintProgressMultiplierGrineer: `[UNTRANSLATED] Hint Progress Multiplier (Grineer)`,
|
||||
cheats_nemesisHintProgressMultiplierCorpus: `[UNTRANSLATED] Hint Progress Multiplier (Corpus)`,
|
||||
cheats_nemesisWeaponFusionMultiplier: `[UNTRANSLATED] Nemesis Weapon Fusion Multiplier`,
|
||||
cheats_nemesisExtraWeapon: `[UNTRANSLATED] Extra Nemesis Weapon / Token On Vanquish (0 to disable)`,
|
||||
cheats_extraMissionRewards: `[UNTRANSLATED] Extra Mission Rewards`,
|
||||
cheats_playerSkillGainsMultiplierSpace: `[UNTRANSLATED] Intrinsics Gains Multiplier (Space)`,
|
||||
cheats_playerSkillGainsMultiplierDrifter: `[UNTRANSLATED] Intrinsics Gains Multiplier (Drifter)`,
|
||||
cheats_extraRelicRewards: `[UNTRANSLATED] Extra Relic Rewards`,
|
||||
cheats_crackRelicForPlatinum: `[UNTRANSLATED] Crack Relic for Platinum`,
|
||||
cheats_relicPlatinumCommon: `[UNTRANSLATED] Platinum on Common Rewards`,
|
||||
cheats_relicPlatinumUncommon: `[UNTRANSLATED] Platinum on Uncommon Rewards`,
|
||||
cheats_relicPlatinumRare: `[UNTRANSLATED] Platinum on Rare Rewards`,
|
||||
|
||||
worldState: `Weltstatus`,
|
||||
worldState_creditBoost: `Event Booster: Credit`,
|
||||
|
||||
@ -78,6 +78,8 @@ dict = {
|
||||
navbar_cheats: `Cheats`,
|
||||
navbar_import: `Import`,
|
||||
inventory_addItems: `Add Items`,
|
||||
inventory_addItemByItemType: `Raw`,
|
||||
inventory_addItemByItemType_warning: `Use this feature at your own risk. It may break your inventory, and you will need to remove items manually if something goes wrong.`,
|
||||
inventory_suits: `Warframes`,
|
||||
inventory_longGuns: `Primary Weapons`,
|
||||
inventory_pistols: `Secondary Weapons`,
|
||||
@ -209,6 +211,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Baro Fully Stocked`,
|
||||
cheats_syndicateMissionsRepeatable: `Syndicate Missions Repeatable`,
|
||||
cheats_unlockAllProfitTakerStages: `Unlock All Profit Taker Stages`,
|
||||
cheats_unlockSucc: `Successfully unlocked.`,
|
||||
cheats_instantFinishRivenChallenge: `Instant Finish Riven Challenge`,
|
||||
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
|
||||
cheats_noResourceExtractorDronesDamage: `No Resource Extractor Drones Damage`,
|
||||
@ -237,6 +240,24 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `Supported syndicate`,
|
||||
cheats_changeButton: `Change`,
|
||||
cheats_markAllAsRead: `Mark Inbox As Read`,
|
||||
cheats_finishInvasionsInOneMission: `Finish Invasions in One Mission`,
|
||||
cheats_gainNoNegativeSyndicateStanding: `Gain No Negative Syndicate Standing`,
|
||||
cheats_nemesisAlwaysCorrect: `Any Guess is Correct`,
|
||||
cheats_nemesisHenchmenKillsMultiplierGrineer: `Rage Progess Multiplier (Grineer)`,
|
||||
cheats_nemesisHenchmenKillsMultiplierCorpus: `Rage Progess Multiplier (Corpus)`,
|
||||
cheats_nemesisAntivirusGainMultiplier: `Antivirus Progress Multiplier`,
|
||||
cheats_nemesisHintProgressMultiplierGrineer: `Hint Progress Multiplier (Grineer)`,
|
||||
cheats_nemesisHintProgressMultiplierCorpus: `Hint Progress Multiplier (Corpus)`,
|
||||
cheats_nemesisWeaponFusionMultiplier: `Nemesis Weapon Fusion Multiplier`,
|
||||
cheats_nemesisExtraWeapon: `Extra Nemesis Weapon / Token On Vanquish (0 to disable)`,
|
||||
cheats_extraMissionRewards: `Extra Mission Rewards`,
|
||||
cheats_playerSkillGainsMultiplierSpace: `Intrinsics Gains Multiplier (Space)`,
|
||||
cheats_playerSkillGainsMultiplierDrifter: `Intrinsics Gains Multiplier (Drifter)`,
|
||||
cheats_extraRelicRewards: `Extra Relic Rewards`,
|
||||
cheats_crackRelicForPlatinum: `Crack Relic for Platinum`,
|
||||
cheats_relicPlatinumCommon: `Platinum on Common Rewards`,
|
||||
cheats_relicPlatinumUncommon: `Platinum on Uncommon Rewards`,
|
||||
cheats_relicPlatinumRare: `Platinum on Rare Rewards`,
|
||||
|
||||
worldState: `World State`,
|
||||
worldState_creditBoost: `Credit Boost`,
|
||||
|
||||
@ -79,6 +79,8 @@ dict = {
|
||||
navbar_cheats: `Trucos`,
|
||||
navbar_import: `Importar`,
|
||||
inventory_addItems: `Agregar objetos`,
|
||||
inventory_addItemByItemType: `[UNTRANSLATED] Raw`,
|
||||
inventory_addItemByItemType_warning: `[UNTRANSLATED] Use this feature at your own risk. It may break your inventory, and you will need to remove items manually if something goes wrong.`,
|
||||
inventory_suits: `Warframes`,
|
||||
inventory_longGuns: `Armas primarias`,
|
||||
inventory_pistols: `Armas secundarias`,
|
||||
@ -210,6 +212,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Baro con stock completo`,
|
||||
cheats_syndicateMissionsRepeatable: `Misiones de sindicato rejugables`,
|
||||
cheats_unlockAllProfitTakerStages: `Desbloquea todas las etapas del Roba-ganancias`,
|
||||
cheats_unlockSucc: `[UNTRANSLATED] Successfully unlocked.`,
|
||||
cheats_instantFinishRivenChallenge: `Terminar desafío de agrietado inmediatamente`,
|
||||
cheats_instantResourceExtractorDrones: `Drones de extracción de recursos instantáneos`,
|
||||
cheats_noResourceExtractorDronesDamage: `Sin daño a los drones extractores de recursos`,
|
||||
@ -238,6 +241,24 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `Sindicatos disponibles`,
|
||||
cheats_changeButton: `Cambiar`,
|
||||
cheats_markAllAsRead: `Marcar bandeja de entrada como leída`,
|
||||
cheats_finishInvasionsInOneMission: `[UNTRANSLATED] Finish Invasions in One Mission`,
|
||||
cheats_gainNoNegativeSyndicateStanding: `[UNTRANSLATED] Gain No Negative Syndicate Standing`,
|
||||
cheats_nemesisAlwaysCorrect: `[UNTRANSLATED] Any Guess is Correct`,
|
||||
cheats_nemesisHenchmenKillsMultiplierGrineer: `[UNTRANSLATED] Rage Progess Multiplier (Grineer)`,
|
||||
cheats_nemesisHenchmenKillsMultiplierCorpus: `[UNTRANSLATED] Rage Progess Multiplier (Corpus)`,
|
||||
cheats_nemesisAntivirusGainMultiplier: `[UNTRANSLATED] Antivirus Progress Multiplier`,
|
||||
cheats_nemesisHintProgressMultiplierGrineer: `[UNTRANSLATED] Hint Progress Multiplier (Grineer)`,
|
||||
cheats_nemesisHintProgressMultiplierCorpus: `[UNTRANSLATED] Hint Progress Multiplier (Corpus)`,
|
||||
cheats_nemesisWeaponFusionMultiplier: `[UNTRANSLATED] Nemesis Weapon Fusion Multiplier`,
|
||||
cheats_nemesisExtraWeapon: `[UNTRANSLATED] Extra Nemesis Weapon / Token On Vanquish (0 to disable)`,
|
||||
cheats_extraMissionRewards: `[UNTRANSLATED] Extra Mission Rewards`,
|
||||
cheats_playerSkillGainsMultiplierSpace: `[UNTRANSLATED] Intrinsics Gains Multiplier (Space)`,
|
||||
cheats_playerSkillGainsMultiplierDrifter: `[UNTRANSLATED] Intrinsics Gains Multiplier (Drifter)`,
|
||||
cheats_extraRelicRewards: `[UNTRANSLATED] Extra Relic Rewards`,
|
||||
cheats_crackRelicForPlatinum: `[UNTRANSLATED] Crack Relic for Platinum`,
|
||||
cheats_relicPlatinumCommon: `[UNTRANSLATED] Platinum on Common Rewards`,
|
||||
cheats_relicPlatinumUncommon: `[UNTRANSLATED] Platinum on Uncommon Rewards`,
|
||||
cheats_relicPlatinumRare: `[UNTRANSLATED] Platinum on Rare Rewards`,
|
||||
|
||||
worldState: `Estado del mundo`,
|
||||
worldState_creditBoost: `Potenciador de Créditos`,
|
||||
|
||||
@ -79,6 +79,8 @@ dict = {
|
||||
navbar_cheats: `Cheats`,
|
||||
navbar_import: `Importer`,
|
||||
inventory_addItems: `Ajouter des items`,
|
||||
inventory_addItemByItemType: `[UNTRANSLATED] Raw`,
|
||||
inventory_addItemByItemType_warning: `[UNTRANSLATED] Use this feature at your own risk. It may break your inventory, and you will need to remove items manually if something goes wrong.`,
|
||||
inventory_suits: `Warframes`,
|
||||
inventory_longGuns: `Armes principales`,
|
||||
inventory_pistols: `Armes secondaires`,
|
||||
@ -210,6 +212,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Stock de Baro au max`,
|
||||
cheats_syndicateMissionsRepeatable: `Mission syndicat répétables`,
|
||||
cheats_unlockAllProfitTakerStages: `Débloquer toutes les étapes du Preneur de Profit`,
|
||||
cheats_unlockSucc: `[UNTRANSLATED] Successfully unlocked.`,
|
||||
cheats_instantFinishRivenChallenge: `Débloquer le challenge Riven instantanément`,
|
||||
cheats_instantResourceExtractorDrones: `Ressources de drones d'extraction instantannées`,
|
||||
cheats_noResourceExtractorDronesDamage: `Aucun dégâts aux drones d'extraction de resources`,
|
||||
@ -238,6 +241,24 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `Allégeance`,
|
||||
cheats_changeButton: `Changer`,
|
||||
cheats_markAllAsRead: `Marquer la boîte de réception comme lue`,
|
||||
cheats_finishInvasionsInOneMission: `[UNTRANSLATED] Finish Invasions in One Mission`,
|
||||
cheats_gainNoNegativeSyndicateStanding: `[UNTRANSLATED] Gain No Negative Syndicate Standing`,
|
||||
cheats_nemesisAlwaysCorrect: `[UNTRANSLATED] Any Guess is Correct`,
|
||||
cheats_nemesisHenchmenKillsMultiplierGrineer: `[UNTRANSLATED] Rage Progess Multiplier (Grineer)`,
|
||||
cheats_nemesisHenchmenKillsMultiplierCorpus: `[UNTRANSLATED] Rage Progess Multiplier (Corpus)`,
|
||||
cheats_nemesisAntivirusGainMultiplier: `[UNTRANSLATED] Antivirus Progress Multiplier`,
|
||||
cheats_nemesisHintProgressMultiplierGrineer: `[UNTRANSLATED] Hint Progress Multiplier (Grineer)`,
|
||||
cheats_nemesisHintProgressMultiplierCorpus: `[UNTRANSLATED] Hint Progress Multiplier (Corpus)`,
|
||||
cheats_nemesisWeaponFusionMultiplier: `[UNTRANSLATED] Nemesis Weapon Fusion Multiplier`,
|
||||
cheats_nemesisExtraWeapon: `[UNTRANSLATED] Extra Nemesis Weapon / Token On Vanquish (0 to disable)`,
|
||||
cheats_extraMissionRewards: `[UNTRANSLATED] Extra Mission Rewards`,
|
||||
cheats_playerSkillGainsMultiplierSpace: `[UNTRANSLATED] Intrinsics Gains Multiplier (Space)`,
|
||||
cheats_playerSkillGainsMultiplierDrifter: `[UNTRANSLATED] Intrinsics Gains Multiplier (Drifter)`,
|
||||
cheats_extraRelicRewards: `[UNTRANSLATED] Extra Relic Rewards`,
|
||||
cheats_crackRelicForPlatinum: `[UNTRANSLATED] Crack Relic for Platinum`,
|
||||
cheats_relicPlatinumCommon: `[UNTRANSLATED] Platinum on Common Rewards`,
|
||||
cheats_relicPlatinumUncommon: `[UNTRANSLATED] Platinum on Uncommon Rewards`,
|
||||
cheats_relicPlatinumRare: `[UNTRANSLATED] Platinum on Rare Rewards`,
|
||||
|
||||
worldState: `Carte Solaire`,
|
||||
worldState_creditBoost: `Booster de Crédit`,
|
||||
|
||||
@ -79,6 +79,8 @@ dict = {
|
||||
navbar_cheats: `Читы`,
|
||||
navbar_import: `Импорт`,
|
||||
inventory_addItems: `Добавить предметы`,
|
||||
inventory_addItemByItemType: `[UNTRANSLATED] Raw`,
|
||||
inventory_addItemByItemType_warning: `Используйте эту функцию на свой страх и риск. Она может повредить ваш инвентарь, и в случае проблем вам придётся удалять предметы вручную.`,
|
||||
inventory_suits: `Варфреймы`,
|
||||
inventory_longGuns: `Основное оружие`,
|
||||
inventory_pistols: `Вторичное оружие`,
|
||||
@ -210,6 +212,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Баро полностью укомплектован`,
|
||||
cheats_syndicateMissionsRepeatable: `Повторять миссии синдиката`,
|
||||
cheats_unlockAllProfitTakerStages: `Разблокировать все этапы Сферы извлечения прибыли`,
|
||||
cheats_unlockSucc: `Успешно разблокировано.`,
|
||||
cheats_instantFinishRivenChallenge: `Мгновенное завершение испытания мода Разлома`,
|
||||
cheats_instantResourceExtractorDrones: `Мгновенно добывающие Дроны-сборщики`,
|
||||
cheats_noResourceExtractorDronesDamage: `Без урона по Дронам-сборщикам`,
|
||||
@ -238,6 +241,24 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `Поддерживаемый синдикат`,
|
||||
cheats_changeButton: `Изменить`,
|
||||
cheats_markAllAsRead: `Пометить все входящие как прочитанные`,
|
||||
cheats_finishInvasionsInOneMission: `Завершать вторжение за одну миссию`,
|
||||
cheats_gainNoNegativeSyndicateStanding: `[UNTRANSLATED] Gain No Negative Syndicate Standing`,
|
||||
cheats_nemesisAlwaysCorrect: `[UNTRANSLATED] Any Guess is Correct`,
|
||||
cheats_nemesisHenchmenKillsMultiplierGrineer: `[UNTRANSLATED] Rage Progess Multiplier (Grineer)`,
|
||||
cheats_nemesisHenchmenKillsMultiplierCorpus: `[UNTRANSLATED] Rage Progess Multiplier (Corpus)`,
|
||||
cheats_nemesisAntivirusGainMultiplier: `[UNTRANSLATED] Antivirus Progress Multiplier`,
|
||||
cheats_nemesisHintProgressMultiplierGrineer: `[UNTRANSLATED] Hint Progress Multiplier (Grineer)`,
|
||||
cheats_nemesisHintProgressMultiplierCorpus: `[UNTRANSLATED] Hint Progress Multiplier (Corpus)`,
|
||||
cheats_nemesisWeaponFusionMultiplier: `[UNTRANSLATED] Nemesis Weapon Fusion Multiplier`,
|
||||
cheats_nemesisExtraWeapon: `[UNTRANSLATED] Extra Nemesis Weapon / Token On Vanquish (0 to disable)`,
|
||||
cheats_extraMissionRewards: `[UNTRANSLATED] Extra Mission Rewards`,
|
||||
cheats_playerSkillGainsMultiplierSpace: `[UNTRANSLATED] Intrinsics Gains Multiplier (Space)`,
|
||||
cheats_playerSkillGainsMultiplierDrifter: `[UNTRANSLATED] Intrinsics Gains Multiplier (Drifter)`,
|
||||
cheats_extraRelicRewards: `[UNTRANSLATED] Extra Relic Rewards`,
|
||||
cheats_crackRelicForPlatinum: `[UNTRANSLATED] Crack Relic for Platinum`,
|
||||
cheats_relicPlatinumCommon: `[UNTRANSLATED] Platinum on Common Rewards`,
|
||||
cheats_relicPlatinumUncommon: `[UNTRANSLATED] Platinum on Uncommon Rewards`,
|
||||
cheats_relicPlatinumRare: `[UNTRANSLATED] Platinum on Rare Rewards`,
|
||||
|
||||
worldState: `Состояние мира`,
|
||||
worldState_creditBoost: `Глобальный бустер Кредитов`,
|
||||
|
||||
@ -79,6 +79,8 @@ dict = {
|
||||
navbar_cheats: `Чити`,
|
||||
navbar_import: `Імпорт`,
|
||||
inventory_addItems: `Додати предмети`,
|
||||
inventory_addItemByItemType: `[UNTRANSLATED] Raw`,
|
||||
inventory_addItemByItemType_warning: `[UNTRANSLATED] Use this feature at your own risk. It may break your inventory, and you will need to remove items manually if something goes wrong.`,
|
||||
inventory_suits: `Ворфрейми`,
|
||||
inventory_longGuns: `Основна зброя`,
|
||||
inventory_pistols: `Допоміжна зброя`,
|
||||
@ -210,6 +212,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `Баро повністю укомплектований`,
|
||||
cheats_syndicateMissionsRepeatable: `Повторювати місії синдиката`,
|
||||
cheats_unlockAllProfitTakerStages: `Розблокувати всі етапи Привласнювачки`,
|
||||
cheats_unlockSucc: `Успішно розблоковано.`,
|
||||
cheats_instantFinishRivenChallenge: `Миттєве завершення випробування модифікатора Розколу`,
|
||||
cheats_instantResourceExtractorDrones: `Миттєво добуваючі Дрони-видобувачі`,
|
||||
cheats_noResourceExtractorDronesDamage: `Без шкоди по Дронам-видобувачам`,
|
||||
@ -238,6 +241,24 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `Підтримуваний синдикат`,
|
||||
cheats_changeButton: `Змінити`,
|
||||
cheats_markAllAsRead: `Помітити всі вхідні як прочитані`,
|
||||
cheats_finishInvasionsInOneMission: `Завершувати вторгнення за одну місію`,
|
||||
cheats_gainNoNegativeSyndicateStanding: `[UNTRANSLATED] Gain No Negative Syndicate Standing`,
|
||||
cheats_nemesisAlwaysCorrect: `[UNTRANSLATED] Any Guess is Correct`,
|
||||
cheats_nemesisHenchmenKillsMultiplierGrineer: `[UNTRANSLATED] Rage Progess Multiplier (Grineer)`,
|
||||
cheats_nemesisHenchmenKillsMultiplierCorpus: `[UNTRANSLATED] Rage Progess Multiplier (Corpus)`,
|
||||
cheats_nemesisAntivirusGainMultiplier: `[UNTRANSLATED] Antivirus Progress Multiplier`,
|
||||
cheats_nemesisHintProgressMultiplierGrineer: `[UNTRANSLATED] Hint Progress Multiplier (Grineer)`,
|
||||
cheats_nemesisHintProgressMultiplierCorpus: `[UNTRANSLATED] Hint Progress Multiplier (Corpus)`,
|
||||
cheats_nemesisWeaponFusionMultiplier: `[UNTRANSLATED] Nemesis Weapon Fusion Multiplier`,
|
||||
cheats_nemesisExtraWeapon: `[UNTRANSLATED] Extra Nemesis Weapon / Token On Vanquish (0 to disable)`,
|
||||
cheats_extraMissionRewards: `[UNTRANSLATED] Extra Mission Rewards`,
|
||||
cheats_playerSkillGainsMultiplierSpace: `[UNTRANSLATED] Intrinsics Gains Multiplier (Space)`,
|
||||
cheats_playerSkillGainsMultiplierDrifter: `[UNTRANSLATED] Intrinsics Gains Multiplier (Drifter)`,
|
||||
cheats_extraRelicRewards: `[UNTRANSLATED] Extra Relic Rewards`,
|
||||
cheats_crackRelicForPlatinum: `[UNTRANSLATED] Crack Relic for Platinum`,
|
||||
cheats_relicPlatinumCommon: `[UNTRANSLATED] Platinum on Common Rewards`,
|
||||
cheats_relicPlatinumUncommon: `[UNTRANSLATED] Platinum on Uncommon Rewards`,
|
||||
cheats_relicPlatinumRare: `[UNTRANSLATED] Platinum on Rare Rewards`,
|
||||
|
||||
worldState: `Стан світу`,
|
||||
worldState_creditBoost: `Глобальне посилення Кредитів`,
|
||||
|
||||
@ -79,6 +79,8 @@ dict = {
|
||||
navbar_cheats: `作弊选项`,
|
||||
navbar_import: `导入`,
|
||||
inventory_addItems: `添加物品`,
|
||||
inventory_addItemByItemType: `[UNTRANSLATED] Raw`,
|
||||
inventory_addItemByItemType_warning: `[UNTRANSLATED] Use this feature at your own risk. It may break your inventory, and you will need to remove items manually if something goes wrong.`,
|
||||
inventory_suits: `战甲`,
|
||||
inventory_longGuns: `主要武器`,
|
||||
inventory_pistols: `次要武器`,
|
||||
@ -210,6 +212,7 @@ dict = {
|
||||
cheats_baroFullyStocked: `虚空商人贩卖所有商品`,
|
||||
cheats_syndicateMissionsRepeatable: `集团任务可重复完成`,
|
||||
cheats_unlockAllProfitTakerStages: `解锁利润收割者圆蛛所有阶段`,
|
||||
cheats_unlockSucc: `[UNTRANSLATED] Successfully unlocked.`,
|
||||
cheats_instantFinishRivenChallenge: `立即完成裂罅挑战`,
|
||||
cheats_instantResourceExtractorDrones: `资源无人机即时完成`,
|
||||
cheats_noResourceExtractorDronesDamage: `资源无人机不会损毁`,
|
||||
@ -238,6 +241,24 @@ dict = {
|
||||
cheats_changeSupportedSyndicate: `支持的集团`,
|
||||
cheats_changeButton: `更改`,
|
||||
cheats_markAllAsRead: `收件箱全部标记为已读`,
|
||||
cheats_finishInvasionsInOneMission: `一场任务完成整场入侵`,
|
||||
cheats_gainNoNegativeSyndicateStanding: `集团声望不倒扣不掉段`,
|
||||
cheats_nemesisAlwaysCorrect: `玄骸密码总是正确`,
|
||||
cheats_nemesisHenchmenKillsMultiplierGrineer: `玄骸怒气倍率 (Grineer)`,
|
||||
cheats_nemesisHenchmenKillsMultiplierCorpus: `玄骸怒气倍率 (Corpus)`,
|
||||
cheats_nemesisAntivirusGainMultiplier: `杀毒进度倍率 (科腐者)`,
|
||||
cheats_nemesisHintProgressMultiplierGrineer: `解密进度倍率 (Grineer)`,
|
||||
cheats_nemesisHintProgressMultiplierCorpus: `解密进度倍率 (Corpus)`,
|
||||
cheats_nemesisWeaponFusionMultiplier: `玄骸武器效价融合倍率`,
|
||||
cheats_nemesisExtraWeapon: `额外玄骸武器/代币 (0为禁用)`,
|
||||
cheats_extraMissionRewards: `额外任务奖励`,
|
||||
cheats_playerSkillGainsMultiplierSpace: `內源之力获取倍率 (九重天)`,
|
||||
cheats_playerSkillGainsMultiplierDrifter: `內源之力获取倍率 (漂泊者)`,
|
||||
cheats_extraRelicRewards: `额外遗物奖励`,
|
||||
cheats_crackRelicForPlatinum: `打开遗物时获得白金`,
|
||||
cheats_relicPlatinumCommon: `普通奖励的白金`,
|
||||
cheats_relicPlatinumUncommon: `罕见奖励的白金`,
|
||||
cheats_relicPlatinumRare: `稀有奖励的白金`,
|
||||
|
||||
worldState: `世界状态配置`,
|
||||
worldState_creditBoost: `现金加成`,
|
||||
|
||||
@ -105,9 +105,6 @@
|
||||
|
||||
/* Completeness */
|
||||
// "skipDefaultLibCheck": true, /* Skip type checking .d.ts files that are included with TypeScript. */
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */,
|
||||
"paths": {
|
||||
"@/*": ["./*"]
|
||||
}
|
||||
"skipLibCheck": true /* Skip type checking all .d.ts files. */
|
||||
}
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user