This commit is contained in:
VampireKitten 2024-06-21 22:01:51 +02:00
commit 3476d6b11c
64 changed files with 1978 additions and 8672 deletions

475
package-lock.json generated
View File

@ -13,7 +13,7 @@
"express": "^5.0.0-beta.3",
"mongoose": "^8.1.1",
"warframe-items": "^1.1262.74",
"warframe-public-export-plus": "^0.2.2",
"warframe-public-export-plus": "^0.2.5",
"warframe-riven-info": "^0.1.0",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1"
@ -22,8 +22,8 @@
"@tsconfig/node20": "^1.0.0",
"@types/express": "^4.17.20",
"@types/morgan": "^1.9.7",
"@typescript-eslint/eslint-plugin": "^6.9.0",
"@typescript-eslint/parser": "^6.2.0",
"@typescript-eslint/eslint-plugin": "^7.13.1",
"@typescript-eslint/parser": "^7.13.1",
"eslint": "^8.56.0",
"eslint-plugin-prettier": "^5.1.3",
"morgan": "^1.10.0",
@ -364,12 +364,6 @@
"@types/send": "*"
}
},
"node_modules/@types/json-schema": {
"version": "7.0.14",
"resolved": "https://registry.npmjs.org/@types/json-schema/-/json-schema-7.0.14.tgz",
"integrity": "sha512-U3PUjAudAdJBeC2pgN8uTIKgxrb4nlDF3SF0++EldXQvQBGkpFZMSnwQiIoDU77tv45VgNkl/L4ouD+rEomujw==",
"dev": true
},
"node_modules/@types/mime": {
"version": "1.3.2",
"resolved": "https://registry.npmjs.org/@types/mime/-/mime-1.3.2.tgz",
@ -403,12 +397,6 @@
"integrity": "sha512-EEhsLsD6UsDM1yFhAvy0Cjr6VwmpMWqFBCb9w07wVugF7w9nfajxLuVmngTIpgS6svCnm6Vaw+MZhoDCKnOfsw==",
"dev": true
},
"node_modules/@types/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/@types/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-MMzuxN3GdFwskAnb6fz0orFvhfqi752yjaXylr0Rp4oDg5H0Zn1IuyRhDVvYOwAXoJirx2xuS16I3WjxnAIHiQ==",
"dev": true
},
"node_modules/@types/send": {
"version": "0.17.1",
"resolved": "https://registry.npmjs.org/@types/send/-/send-0.17.1.tgz",
@ -460,33 +448,31 @@
}
},
"node_modules/@typescript-eslint/eslint-plugin": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-6.9.0.tgz",
"integrity": "sha512-lgX7F0azQwRPB7t7WAyeHWVfW1YJ9NIgd9mvGhfQpRY56X6AVf8mwM8Wol+0z4liE7XX3QOt8MN1rUKCfSjRIA==",
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-7.13.1.tgz",
"integrity": "sha512-kZqi+WZQaZfPKnsflLJQCz6Ze9FFSMfXrrIOcyargekQxG37ES7DJNpJUE9Q/X5n3yTIP/WPutVNzgknQ7biLg==",
"dev": true,
"dependencies": {
"@eslint-community/regexpp": "^4.5.1",
"@typescript-eslint/scope-manager": "6.9.0",
"@typescript-eslint/type-utils": "6.9.0",
"@typescript-eslint/utils": "6.9.0",
"@typescript-eslint/visitor-keys": "6.9.0",
"debug": "^4.3.4",
"@eslint-community/regexpp": "^4.10.0",
"@typescript-eslint/scope-manager": "7.13.1",
"@typescript-eslint/type-utils": "7.13.1",
"@typescript-eslint/utils": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1",
"graphemer": "^1.4.0",
"ignore": "^5.2.4",
"ignore": "^5.3.1",
"natural-compare": "^1.4.0",
"semver": "^7.5.4",
"ts-api-utils": "^1.0.1"
"ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
"node": "^18.18.0 || >=20.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"@typescript-eslint/parser": "^6.0.0 || ^6.0.0-alpha",
"eslint": "^7.0.0 || ^8.0.0"
"@typescript-eslint/parser": "^7.0.0",
"eslint": "^8.56.0"
},
"peerDependenciesMeta": {
"typescript": {
@ -494,97 +480,27 @@
}
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/scope-manager": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz",
"integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.9.0",
"@typescript-eslint/visitor-keys": "6.9.0"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/types": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz",
"integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==",
"dev": true,
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/@typescript-eslint/visitor-keys": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz",
"integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.9.0",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/eslint-plugin/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/@typescript-eslint/parser": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-6.2.0.tgz",
"integrity": "sha512-igVYOqtiK/UsvKAmmloQAruAdUHihsOCvplJpplPZ+3h4aDkC/UKZZNKgB6h93ayuYLuEymU3h8nF1xMRbh37g==",
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/parser/-/parser-7.13.1.tgz",
"integrity": "sha512-1ELDPlnLvDQ5ybTSrMhRTFDfOQEOXNM+eP+3HT/Yq7ruWpciQw+Avi73pdEbA4SooCawEWo3dtYbF68gN7Ed1A==",
"dev": true,
"dependencies": {
"@typescript-eslint/scope-manager": "6.2.0",
"@typescript-eslint/types": "6.2.0",
"@typescript-eslint/typescript-estree": "6.2.0",
"@typescript-eslint/visitor-keys": "6.2.0",
"@typescript-eslint/scope-manager": "7.13.1",
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/typescript-estree": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1",
"debug": "^4.3.4"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
"node": "^18.18.0 || >=20.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^7.0.0 || ^8.0.0"
"eslint": "^8.56.0"
},
"peerDependenciesMeta": {
"typescript": {
@ -593,9 +509,9 @@
}
},
"node_modules/@typescript-eslint/parser/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
@ -616,16 +532,16 @@
"dev": true
},
"node_modules/@typescript-eslint/scope-manager": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.2.0.tgz",
"integrity": "sha512-1ZMNVgm5nnHURU8ZSJ3snsHzpFeNK84rdZjluEVBGNu7jDymfqceB3kdIZ6A4xCfEFFhRIB6rF8q/JIqJd2R0Q==",
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-7.13.1.tgz",
"integrity": "sha512-adbXNVEs6GmbzaCpymHQ0MB6E4TqoiVbC0iqG3uijR8ZYfpAXMGttouQzF4Oat3P2GxDVIrg7bMI/P65LiQZdg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.2.0",
"@typescript-eslint/visitor-keys": "6.2.0"
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
"node": "^18.18.0 || >=20.0.0"
},
"funding": {
"type": "opencollective",
@ -633,25 +549,25 @@
}
},
"node_modules/@typescript-eslint/type-utils": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-6.9.0.tgz",
"integrity": "sha512-XXeahmfbpuhVbhSOROIzJ+b13krFmgtc4GlEuu1WBT+RpyGPIA4Y/eGnXzjbDj5gZLzpAXO/sj+IF/x2GtTMjQ==",
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/type-utils/-/type-utils-7.13.1.tgz",
"integrity": "sha512-aWDbLu1s9bmgPGXSzNCxELu+0+HQOapV/y+60gPXafR8e2g1Bifxzevaa+4L2ytCWm+CHqpELq4CSoN9ELiwCg==",
"dev": true,
"dependencies": {
"@typescript-eslint/typescript-estree": "6.9.0",
"@typescript-eslint/utils": "6.9.0",
"@typescript-eslint/typescript-estree": "7.13.1",
"@typescript-eslint/utils": "7.13.1",
"debug": "^4.3.4",
"ts-api-utils": "^1.0.1"
"ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
"node": "^18.18.0 || >=20.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^7.0.0 || ^8.0.0"
"eslint": "^8.56.0"
},
"peerDependenciesMeta": {
"typescript": {
@ -659,67 +575,10 @@
}
}
},
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/types": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz",
"integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==",
"dev": true,
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/typescript-estree": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz",
"integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.9.0",
"@typescript-eslint/visitor-keys": "6.9.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.5.4",
"ts-api-utils": "^1.0.1"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/type-utils/node_modules/@typescript-eslint/visitor-keys": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz",
"integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.9.0",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/type-utils/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
@ -740,12 +599,12 @@
"dev": true
},
"node_modules/@typescript-eslint/types": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.2.0.tgz",
"integrity": "sha512-1nRRaDlp/XYJQLvkQJG5F3uBTno5SHPT7XVcJ5n1/k2WfNI28nJsvLakxwZRNY5spuatEKO7d5nZWsQpkqXwBA==",
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-7.13.1.tgz",
"integrity": "sha512-7K7HMcSQIAND6RBL4kDl24sG/xKM13cA85dc7JnmQXw2cBDngg7c19B++JzvJHRG3zG36n9j1i451GBzRuHchw==",
"dev": true,
"engines": {
"node": "^16.0.0 || >=18.0.0"
"node": "^18.18.0 || >=20.0.0"
},
"funding": {
"type": "opencollective",
@ -753,21 +612,22 @@
}
},
"node_modules/@typescript-eslint/typescript-estree": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.2.0.tgz",
"integrity": "sha512-Mts6+3HQMSM+LZCglsc2yMIny37IhUgp1Qe8yJUYVyO6rHP7/vN0vajKu3JvHCBIy8TSiKddJ/Zwu80jhnGj1w==",
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-7.13.1.tgz",
"integrity": "sha512-uxNr51CMV7npU1BxZzYjoVz9iyjckBduFBP0S5sLlh1tXYzHzgZ3BR9SVsNed+LmwKrmnqN3Kdl5t7eZ5TS1Yw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.2.0",
"@typescript-eslint/visitor-keys": "6.2.0",
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/visitor-keys": "7.13.1",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.5.4",
"ts-api-utils": "^1.0.1"
"minimatch": "^9.0.4",
"semver": "^7.6.0",
"ts-api-utils": "^1.3.0"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
"node": "^18.18.0 || >=20.0.0"
},
"funding": {
"type": "opencollective",
@ -779,10 +639,19 @@
}
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/brace-expansion": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
"dev": true,
"dependencies": {
"balanced-match": "^1.0.0"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"version": "4.3.5",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.5.tgz",
"integrity": "sha512-pt0bNEmneDIvdL1Xsd9oDQ/wrQRkXDT4AUWlNZNPKvW5x/jyO9VFXkJUP07vQ2upmw5PlaITaPKc31jK13V+jg==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
@ -796,6 +665,21 @@
}
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/minimatch": {
"version": "9.0.4",
"resolved": "https://registry.npmjs.org/minimatch/-/minimatch-9.0.4.tgz",
"integrity": "sha512-KqWh+VchfxcMNRAJjj2tnsSJdNbHsVgnkBhTNrW7AjVo6OvLtxw8zfT9oLw1JSohlFzJ8jCoTgaoXvJ+kHt6fw==",
"dev": true,
"dependencies": {
"brace-expansion": "^2.0.1"
},
"engines": {
"node": ">=16 || 14 >=14.17"
},
"funding": {
"url": "https://github.com/sponsors/isaacs"
}
},
"node_modules/@typescript-eslint/typescript-estree/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
@ -803,138 +687,38 @@
"dev": true
},
"node_modules/@typescript-eslint/utils": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-6.9.0.tgz",
"integrity": "sha512-5Wf+Jsqya7WcCO8me504FBigeQKVLAMPmUzYgDbWchINNh1KJbxCgVya3EQ2MjvJMVeXl3pofRmprqX6mfQkjQ==",
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/utils/-/utils-7.13.1.tgz",
"integrity": "sha512-h5MzFBD5a/Gh/fvNdp9pTfqJAbuQC4sCN2WzuXme71lqFJsZtLbjxfSk4r3p02WIArOF9N94pdsLiGutpDbrXQ==",
"dev": true,
"dependencies": {
"@eslint-community/eslint-utils": "^4.4.0",
"@types/json-schema": "^7.0.12",
"@types/semver": "^7.5.0",
"@typescript-eslint/scope-manager": "6.9.0",
"@typescript-eslint/types": "6.9.0",
"@typescript-eslint/typescript-estree": "6.9.0",
"semver": "^7.5.4"
"@typescript-eslint/scope-manager": "7.13.1",
"@typescript-eslint/types": "7.13.1",
"@typescript-eslint/typescript-estree": "7.13.1"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
"node": "^18.18.0 || >=20.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependencies": {
"eslint": "^7.0.0 || ^8.0.0"
"eslint": "^8.56.0"
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/scope-manager": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/scope-manager/-/scope-manager-6.9.0.tgz",
"integrity": "sha512-1R8A9Mc39n4pCCz9o79qRO31HGNDvC7UhPhv26TovDsWPBDx+Sg3rOZdCELIA3ZmNoWAuxaMOT7aWtGRSYkQxw==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.9.0",
"@typescript-eslint/visitor-keys": "6.9.0"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/types": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/types/-/types-6.9.0.tgz",
"integrity": "sha512-+KB0lbkpxBkBSiVCuQvduqMJy+I1FyDbdwSpM3IoBS7APl4Bu15lStPjgBIdykdRqQNYqYNMa8Kuidax6phaEw==",
"dev": true,
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/typescript-estree": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/typescript-estree/-/typescript-estree-6.9.0.tgz",
"integrity": "sha512-NJM2BnJFZBEAbCfBP00zONKXvMqihZCrmwCaik0UhLr0vAgb6oguXxLX1k00oQyD+vZZ+CJn3kocvv2yxm4awQ==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.9.0",
"@typescript-eslint/visitor-keys": "6.9.0",
"debug": "^4.3.4",
"globby": "^11.1.0",
"is-glob": "^4.0.3",
"semver": "^7.5.4",
"ts-api-utils": "^1.0.1"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
},
"peerDependenciesMeta": {
"typescript": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/utils/node_modules/@typescript-eslint/visitor-keys": {
"version": "6.9.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.9.0.tgz",
"integrity": "sha512-dGtAfqjV6RFOtIP8I0B4ZTBRrlTT8NHHlZZSchQx3qReaoDeXhYM++M4So2AgFK9ZB0emRPA6JI1HkafzA2Ibg==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.9.0",
"eslint-visitor-keys": "^3.4.1"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
},
"funding": {
"type": "opencollective",
"url": "https://opencollective.com/typescript-eslint"
}
},
"node_modules/@typescript-eslint/utils/node_modules/debug": {
"version": "4.3.4",
"resolved": "https://registry.npmjs.org/debug/-/debug-4.3.4.tgz",
"integrity": "sha512-PRWFHuSU3eDtQJPvnNY7Jcket1j0t5OuOsFzPPzsekD52Zl8qUfFIPEiswXqIvHWGVHOgX+7G/vCNNhehwxfkQ==",
"dev": true,
"dependencies": {
"ms": "2.1.2"
},
"engines": {
"node": ">=6.0"
},
"peerDependenciesMeta": {
"supports-color": {
"optional": true
}
}
},
"node_modules/@typescript-eslint/utils/node_modules/ms": {
"version": "2.1.2",
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.2.tgz",
"integrity": "sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w==",
"dev": true
},
"node_modules/@typescript-eslint/visitor-keys": {
"version": "6.2.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-6.2.0.tgz",
"integrity": "sha512-QbaYUQVKKo9bgCzpjz45llCfwakyoxHetIy8CAvYCtd16Zu1KrpzNHofwF8kGkpPOxZB2o6kz+0nqH8ZkIzuoQ==",
"version": "7.13.1",
"resolved": "https://registry.npmjs.org/@typescript-eslint/visitor-keys/-/visitor-keys-7.13.1.tgz",
"integrity": "sha512-k/Bfne7lrP7hcb7m9zSsgcBmo+8eicqqfNAJ7uUY+jkTFpKeH2FSkWpFRtimBxgkyvqfu9jTPRbYOvud6isdXA==",
"dev": true,
"dependencies": {
"@typescript-eslint/types": "6.2.0",
"eslint-visitor-keys": "^3.4.1"
"@typescript-eslint/types": "7.13.1",
"eslint-visitor-keys": "^3.4.3"
},
"engines": {
"node": "^16.0.0 || >=18.0.0"
"node": "^18.18.0 || >=20.0.0"
},
"funding": {
"type": "opencollective",
@ -1848,9 +1632,9 @@
"dev": true
},
"node_modules/fast-glob": {
"version": "3.3.1",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.1.tgz",
"integrity": "sha512-kNFPyjhh5cKjrUltxs+wFx+ZkbRaxxmZ+X0ZU31SOsxCEtP9VPgtq2teZw1DebupL5GmDaNQ6yKMMVcM41iqDg==",
"version": "3.3.2",
"resolved": "https://registry.npmjs.org/fast-glob/-/fast-glob-3.3.2.tgz",
"integrity": "sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow==",
"dev": true,
"dependencies": {
"@nodelib/fs.stat": "^2.0.2",
@ -2245,9 +2029,9 @@
}
},
"node_modules/ignore": {
"version": "5.2.4",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.2.4.tgz",
"integrity": "sha512-MAb38BcSbH0eHNBxn7ql2NH/kX33OkB3lZ1BNdh7ENeRChHTYsTvWrMubiIAMNS2llXEEgZ1MUOBtXChP3kaFQ==",
"version": "5.3.1",
"resolved": "https://registry.npmjs.org/ignore/-/ignore-5.3.1.tgz",
"integrity": "sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw==",
"dev": true,
"engines": {
"node": ">= 4"
@ -2496,18 +2280,6 @@
"resolved": "https://registry.npmjs.org/ms/-/ms-2.1.3.tgz",
"integrity": "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="
},
"node_modules/lru-cache": {
"version": "6.0.0",
"resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-6.0.0.tgz",
"integrity": "sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA==",
"dev": true,
"dependencies": {
"yallist": "^4.0.0"
},
"engines": {
"node": ">=10"
}
},
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
@ -2550,12 +2322,12 @@
}
},
"node_modules/micromatch": {
"version": "4.0.5",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.5.tgz",
"integrity": "sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA==",
"version": "4.0.7",
"resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.7.tgz",
"integrity": "sha512-LPP/3KorzCwBxfeUuZmaR6bG2kdeHSbe0P2tY3FLRU4vYrjYz5hI4QZwV0njUx3jeuKe67YukQ1LSPZBKDqO/Q==",
"dev": true,
"dependencies": {
"braces": "^3.0.2",
"braces": "^3.0.3",
"picomatch": "^2.3.1"
},
"engines": {
@ -3261,13 +3033,10 @@
"integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
},
"node_modules/semver": {
"version": "7.5.4",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.5.4.tgz",
"integrity": "sha512-1bCSESV6Pv+i21Hvpxp3Dx+pSD8lIPt8uVjRrxAUt/nbswYc+tK6Y2btiULjd4+fnq15PX+nqQDC7Oft7WkwcA==",
"version": "7.6.2",
"resolved": "https://registry.npmjs.org/semver/-/semver-7.6.2.tgz",
"integrity": "sha512-FNAIBWCx9qcRhoHcgcJ0gvU7SN1lYU2ZXuSfl04bSC5OpvDHFyJCjdNHomPXxjQlCBU67YW64PzY7/VIEH7F2w==",
"dev": true,
"dependencies": {
"lru-cache": "^6.0.0"
},
"bin": {
"semver": "bin/semver.js"
},
@ -3658,12 +3427,12 @@
}
},
"node_modules/ts-api-utils": {
"version": "1.0.1",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.0.1.tgz",
"integrity": "sha512-lC/RGlPmwdrIBFTX59wwNzqh7aR2otPNPR/5brHZm/XKFYKsfqxihXUe9pU3JI+3vGkl+vyCoNNnPhJn3aLK1A==",
"version": "1.3.0",
"resolved": "https://registry.npmjs.org/ts-api-utils/-/ts-api-utils-1.3.0.tgz",
"integrity": "sha512-UQMIo7pb8WRomKR1/+MFVLTroIvDVtMX3K6OUir8ynLyzB8Jeriont2bTAtmNPa1ekAgN7YPDyf6V+ygrdU+eQ==",
"dev": true,
"engines": {
"node": ">=16.13.0"
"node": ">=16"
},
"peerDependencies": {
"typescript": ">=4.2.0"
@ -3909,9 +3678,9 @@
}
},
"node_modules/warframe-public-export-plus": {
"version": "0.2.2",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.2.2.tgz",
"integrity": "sha512-PAsiyiRDqXcsUwZTweihwrSksd+GT3USrbHwS/TrJUC3TqLS0Ng24OfefFKPWOmPfMxDbdkg2zV39uq72iZ/Yg=="
"version": "0.2.5",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.2.5.tgz",
"integrity": "sha512-IsS2Z14CeTpGSpfeUxqTi8wAQjQ6qjh2kV8RC9St5hcDmII3NpwEFXmStEqz7r+JPfea72D3cZMMl+4QLHqvXw=="
},
"node_modules/warframe-riven-info": {
"version": "0.1.0",
@ -4061,12 +3830,6 @@
"node": ">=10"
}
},
"node_modules/yallist": {
"version": "4.0.0",
"resolved": "https://registry.npmjs.org/yallist/-/yallist-4.0.0.tgz",
"integrity": "sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A==",
"dev": true
},
"node_modules/yargs": {
"version": "16.2.0",
"resolved": "https://registry.npmjs.org/yargs/-/yargs-16.2.0.tgz",

View File

@ -17,7 +17,7 @@
"express": "^5.0.0-beta.3",
"mongoose": "^8.1.1",
"warframe-items": "^1.1262.74",
"warframe-public-export-plus": "^0.2.2",
"warframe-public-export-plus": "^0.2.5",
"warframe-riven-info": "^0.1.0",
"winston": "^3.11.0",
"winston-daily-rotate-file": "^4.7.1"
@ -26,8 +26,8 @@
"@tsconfig/node20": "^1.0.0",
"@types/express": "^4.17.20",
"@types/morgan": "^1.9.7",
"@typescript-eslint/eslint-plugin": "^6.9.0",
"@typescript-eslint/parser": "^6.2.0",
"@typescript-eslint/eslint-plugin": "^7.13.1",
"@typescript-eslint/parser": "^7.13.1",
"eslint": "^8.56.0",
"eslint-plugin-prettier": "^5.1.3",
"morgan": "^1.10.0",

View File

@ -4,6 +4,7 @@ import { IUpdateGlyphRequest } from "@/src/types/requestTypes";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory } from "@/src/services/inventoryService";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const addFriendImageController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const json = getJSONfromString(req.body.toString()) as IUpdateGlyphRequest;

View File

@ -3,11 +3,11 @@
import { RequestHandler } from "express";
import { logger } from "@/src/utils/logger";
import { getItemByBlueprint, getItemCategoryByUniqueName } from "@/src/services/itemDataService";
import { getRecipe } from "@/src/services/itemDataService";
import { IOid } from "@/src/types/commonTypes";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory } from "@/src/services/inventoryService";
import { getInventory, updateCurrency, addItem, addMiscItems, addRecipes } from "@/src/services/inventoryService";
export interface IClaimCompletedRecipeRequest {
RecipeIds: IOid[];
@ -19,12 +19,10 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
const accountId = await getAccountIdForRequest(req);
if (!accountId) throw new Error("no account id");
console.log(claimCompletedRecipeRequest);
const inventory = await getInventory(accountId);
const pendingRecipe = inventory.PendingRecipes.find(
recipe => recipe._id?.toString() === claimCompletedRecipeRequest.RecipeIds[0].$oid
);
console.log(pendingRecipe);
if (!pendingRecipe) {
logger.error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`);
throw new Error(`no pending recipe found with id ${claimCompletedRecipeRequest.RecipeIds[0].$oid}`);
@ -36,29 +34,55 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
// throw new Error(`recipe ${pendingRecipe._id} is not ready to be completed`);
// }
//get completed Items
const completedItemName = getItemByBlueprint(pendingRecipe.ItemType)?.uniqueName;
inventory.PendingRecipes.pull(pendingRecipe._id);
await inventory.save();
if (!completedItemName) {
const recipe = getRecipe(pendingRecipe.ItemType);
if (!recipe) {
logger.error(`no completed item found for recipe ${pendingRecipe._id}`);
throw new Error(`no completed item found for recipe ${pendingRecipe._id}`);
}
const itemCategory = getItemCategoryByUniqueName(completedItemName) as keyof typeof inventory;
console.log(itemCategory);
//TODO: remove all Schema.Mixed for inventory[itemCategory] not to be any
//add item
//inventory[itemCategory].
//add additional item components like mods or weapons for a sentinel.
//const additionalItemComponents = itemComponents[uniqueName]
//add these items to inventory
//return changes as InventoryChanges
if (req.query.cancel) {
const currencyChanges = await updateCurrency(recipe.buildPrice * -1, false, accountId);
//remove pending recipe
inventory.PendingRecipes.pull(pendingRecipe._id);
// await inventory.save();
const inventory = await getInventory(accountId);
addMiscItems(inventory, recipe.ingredients);
await inventory.save();
logger.debug("Claiming Completed Recipe", { completedItemName });
// Not a bug: In the specific case of cancelling a recipe, InventoryChanges are expected to be the root.
res.json({
...currencyChanges,
MiscItems: recipe.ingredients
});
} else {
logger.debug("Claiming Recipe", { recipe, pendingRecipe });
let InventoryChanges = {};
if (recipe.consumeOnUse) {
const recipeChanges = [
{
ItemType: pendingRecipe.ItemType,
ItemCount: -1
}
];
res.json({ InventoryChanges: {} });
InventoryChanges = { ...InventoryChanges, Recipes: recipeChanges };
const inventory = await getInventory(accountId);
addRecipes(inventory, recipeChanges);
await inventory.save();
}
if (req.query.rush) {
InventoryChanges = {
...InventoryChanges,
...(await updateCurrency(recipe.skipBuildTimePrice, true, accountId))
};
}
res.json({
InventoryChanges: {
...InventoryChanges,
...(await addItem(accountId, recipe.resultType, recipe.num)).InventoryChanges
}
});
}
};

View File

@ -5,6 +5,7 @@ import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
import { Guild } from "@/src/models/guildModel";
import { ICreateGuildRequest } from "@/src/types/guildTypes";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const createGuildController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const payload: ICreateGuildRequest = getJSONfromString(req.body.toString());

View File

@ -0,0 +1,42 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory } from "@/src/services/inventoryService";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { WeaponTypeInternal } from "@/src/services/itemDataService";
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const evolveWeaponController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const payload = getJSONfromString(req.body.toString()) as IEvolveWeaponRequest;
console.assert(payload.Action == "EWA_INSTALL");
// TODO: We should remove the Genesis item & its resources, but currently we don't know these "recipes".
const item = inventory[payload.Category].find(item => item._id.toString() == (req.query.ItemId as string))!;
item.Features ??= 0;
item.Features |= EquipmentFeatures.INCARNON_GENESIS;
item.SkillTree = "0";
inventory.EvolutionProgress ??= [];
if (!inventory.EvolutionProgress.find(entry => entry.ItemType == payload.EvoType)) {
inventory.EvolutionProgress.push({
Progress: 0,
Rank: 1,
ItemType: payload.EvoType
});
}
await inventory.save();
res.end();
};
interface IEvolveWeaponRequest {
Action: "EWA_INSTALL";
Category: WeaponTypeInternal;
Recipe: string; // e.g. "/Lotus/Types/Items/MiscItems/IncarnonAdapters/UnlockerBlueprints/DespairIncarnonBlueprint"
UninstallRecipe: "";
EvoType: string; // e.g. "/Lotus/Weapons/Tenno/ThrowingWeapons/StalkerKunai"
}

View File

@ -5,6 +5,7 @@ import { IMiscItem, TFocusPolarity } from "@/src/types/inventoryTypes/inventoryT
import { logger } from "@/src/utils/logger";
import baseFocusPointCosts from "@/static/json/baseFocusPointCosts.json";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const focusController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
switch (req.query.op) {

View File

@ -4,6 +4,7 @@ import { Guild } from "@/src/models/guildModel";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { toOid } from "@/src/helpers/inventoryHelpers";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const getGuildController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await Inventory.findOne({ accountOwnerId: accountId });

View File

@ -4,6 +4,7 @@ import { Guild } from "@/src/models/guildModel";
import { IDojoClient, IDojoComponentClient } from "@/src/types/guildTypes";
import { toOid, toMongoDate } from "@/src/helpers/inventoryHelpers";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const getGuildDojoController: RequestHandler = async (req, res) => {
const guildId = req.query.guildId as string;

View File

@ -0,0 +1,7 @@
import { RequestHandler } from "express";
import getVendorInfoResponse from "@/static/fixed_responses/getVendorInfo.json";
export const getVendorInfoController: RequestHandler = (req, res) => {
console.assert(req.query.vendor == "/Lotus/Types/Game/VendorManifests/Ostron/MaskSalesmanManifest");
res.json(getVendorInfoResponse);
};

View File

@ -4,6 +4,7 @@ import { createNewSession } from "@/src/managers/sessionManager";
import { logger } from "@/src/utils/logger";
import { ISession } from "@/src/types/session";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const hostSessionController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const hostSessionRequest = JSON.parse(req.body as string) as ISession;

View File

@ -0,0 +1,89 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { getInventory, addMiscItems } from "@/src/services/inventoryService";
import { IOid } from "@/src/types/commonTypes";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const infestedFoundryController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const payload = getJSONfromString(req.body.toString());
switch (req.query.mode) {
case "s": {
// shard installation
const request = payload as IShardInstallRequest;
const inventory = await getInventory(accountId);
const suit = inventory.Suits.find(suit => suit._id.toString() == request.SuitId.$oid)!;
if (
!suit.ArchonCrystalUpgrades ||
suit.ArchonCrystalUpgrades.length != 5 // we shouldn't have an array like this, but older inventories may disagree...
) {
suit.ArchonCrystalUpgrades = [{}, {}, {}, {}, {}];
}
suit.ArchonCrystalUpgrades[request.Slot] = {
UpgradeType: request.UpgradeType,
Color: request.Color
};
const miscItemChanges = [
{
ItemType: colorToShard[request.Color],
ItemCount: -1
}
];
addMiscItems(inventory, miscItemChanges);
await inventory.save();
res.json({
InventoryChanges: {
MiscItems: miscItemChanges
}
});
break;
}
case "n": {
// name the beast
const inventory = await getInventory(accountId);
inventory.InfestedFoundry ??= {};
inventory.InfestedFoundry.Name = payload.newName as string;
await inventory.save();
res.json({
InventoryChanges: {
InfestedFoundry: {
Name: inventory.InfestedFoundry.Name
}
}
});
break;
}
case "o": // offerings update
// {"OfferingsIndex":540,"SuitTypes":["/Lotus/Powersuits/PaxDuviricus/PaxDuviricusBaseSuit","/Lotus/Powersuits/Nezha/NezhaBaseSuit","/Lotus/Powersuits/Devourer/DevourerBaseSuit"],"Extra":false}
res.status(404).end();
break;
default:
throw new Error(`unhandled infestedFoundry mode: ${req.query.mode}`);
}
};
interface IShardInstallRequest {
SuitId: IOid;
Slot: number;
UpgradeType: string;
Color: string;
}
const colorToShard: Record<string, string> = {
ACC_RED: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalAmar",
ACC_RED_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalAmarMythic",
ACC_YELLOW: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalNira",
ACC_YELLOW_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalNiraMythic",
ACC_BLUE: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalBoreal",
ACC_BLUE_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalBorealMythic",
ACC_GREEN: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalGreen",
ACC_GREEN_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalGreenMythic",
ACC_ORANGE: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalOrange",
ACC_ORANGE_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalOrangeMythic",
ACC_PURPLE: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalViolet",
ACC_PURPLE_MYTHIC: "/Lotus/Types/Gameplay/NarmerSorties/ArchonCrystalVioletMythic"
};

View File

@ -1,18 +1,15 @@
/* eslint-disable @typescript-eslint/no-misused-promises */
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { toInventoryResponse } from "@/src/helpers/inventoryHelpers";
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
import { Request, RequestHandler, Response } from "express";
import { config } from "@/src/services/configService";
import allMissions from "@/static/fixed_responses/allMissions.json";
import allQuestKeys from "@/static/fixed_responses/allQuestKeys.json";
import allShipDecorations from "@/static/fixed_responses/allShipDecorations.json";
import allFlavourItems from "@/static/fixed_responses/allFlavourItems.json";
import allSkins from "@/static/fixed_responses/allSkins.json";
import { ILoadoutDatabase } from "@/src/types/saveLoadoutTypes";
import { IShipInventory, IFlavourItem } from "@/src/types/inventoryTypes/inventoryTypes";
import { IShipInventory } from "@/src/types/inventoryTypes/inventoryTypes";
import { ExportCustoms, ExportFlavour, ExportKeys, ExportResources } from "warframe-public-export-plus";
const inventoryController: RequestHandler = async (request: Request, response: Response) => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const inventoryController: RequestHandler = async (request, response) => {
let accountId;
try {
accountId = await getAccountIdForRequest(request);
@ -51,46 +48,73 @@ const inventoryController: RequestHandler = async (request: Request, response: R
}
if (config.unlockAllQuests) {
for (const questKey of allQuestKeys) {
if (!inventoryResponse.QuestKeys.find(quest => quest.ItemType == questKey)) {
inventoryResponse.QuestKeys.push({ ItemType: questKey });
for (const [k, v] of Object.entries(ExportKeys)) {
if ("chainStages" in v) {
if (!inventoryResponse.QuestKeys.find(quest => quest.ItemType == k)) {
inventoryResponse.QuestKeys.push({ ItemType: k });
}
}
}
}
if (config.completeAllQuests) {
for (const quest of inventoryResponse.QuestKeys) {
quest.Completed = true;
quest.Progress = [
{
c: 0,
i: false,
m: false,
b: []
}
];
}
inventoryResponse.ArchwingEnabled = true;
// Skip "Watch The Maker"
inventoryResponse.NodeIntrosCompleted.push("/Lotus/Levels/Cinematics/NewWarIntro/NewWarStageTwo.level");
}
if (config.unlockAllShipDecorations) {
inventoryResponse.ShipDecorations = [];
for (const [uniqueName, item] of Object.entries(ExportResources)) {
if (item.productCategory == "ShipDecorations") {
inventoryResponse.ShipDecorations.push({ ItemType: uniqueName, ItemCount: 1 });
}
}
}
if (config.unlockAllShipDecorations) inventoryResponse.ShipDecorations = allShipDecorations;
if (config.unlockAllFlavourItems) inventoryResponse.FlavourItems = allFlavourItems satisfies IFlavourItem[];
if (config.unlockAllFlavourItems) {
inventoryResponse.FlavourItems = [];
for (const uniqueName in ExportFlavour) {
inventoryResponse.FlavourItems.push({ ItemType: uniqueName });
}
}
if (config.unlockAllSkins) {
inventoryResponse.WeaponSkins = [];
for (const skin of allSkins) {
for (const uniqueName in ExportCustoms) {
inventoryResponse.WeaponSkins.push({
ItemId: {
$oid: "000000000000000000000000"
},
ItemType: skin
ItemType: uniqueName
});
}
}
if (
typeof config.spoofMasteryRank === "number" &&
config.spoofMasteryRank >= 0 &&
config.spoofMasteryRank <= 5030
) {
if (typeof config.spoofMasteryRank === "number" && config.spoofMasteryRank >= 0) {
inventoryResponse.PlayerLevel = config.spoofMasteryRank;
inventoryResponse.XPInfo = [];
let numFrames = getExpRequiredForMr(config.spoofMasteryRank) / 6000;
while (numFrames-- > 0) {
inventoryResponse.XPInfo.push({
ItemType: "/Lotus/Powersuits/Mag/Mag",
XP: 1_600_000
});
if (!("xpBasedLevelCapDisabled" in request.query)) {
// This client has not been patched to accept any mastery rank, need to fake the XP.
inventoryResponse.XPInfo = [];
let numFrames = getExpRequiredForMr(Math.min(config.spoofMasteryRank, 5030)) / 6000;
while (numFrames-- > 0) {
inventoryResponse.XPInfo.push({
ItemType: "/Lotus/Powersuits/Mag/Mag",
XP: 1_600_000
});
}
}
}

View File

@ -2,7 +2,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
import { updateCurrency } from "@/src/services/inventoryService";
import { RequestHandler } from "express";
import { updateSlots } from "@/src/services/inventoryService";
import { SlotNameToInventoryName } from "@/src/types/purchaseTypes";
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
/*
loadout slots are additionally purchased slots only
@ -28,7 +28,7 @@ export const inventorySlotsController: RequestHandler = async (req, res) => {
//TODO: check which slot was purchased because pvpBonus is also possible
const currencyChanges = await updateCurrency(20, true, accountId);
await updateSlots(accountId, SlotNameToInventoryName.LOADOUT, 1, 1);
await updateSlots(accountId, InventorySlot.PVE_LOADOUTS, 1, 1);
//console.log({ InventoryChanges: currencyChanges }, " added loadout changes:");

View File

@ -43,7 +43,7 @@ const loginController: RequestHandler = async (request, response) => {
platformCDNs: platformCDNs,
NRS: [config.myAddress],
DTLS: DTLS,
IRC: [config.myAddress],
IRC: config.myIrcAddresses ?? [config.myAddress],
HUB: HUB,
BuildLabel: buildConfig.buildLabel,
MatchmakingBuildId: buildConfig.matchmakingBuildId
@ -79,7 +79,7 @@ const loginController: RequestHandler = async (request, response) => {
platformCDNs: platformCDNs,
NRS: [config.myAddress],
DTLS: DTLS,
IRC: [config.myAddress],
IRC: config.myIrcAddresses ?? [config.myAddress],
HUB: HUB,
BuildLabel: buildConfig.buildLabel,
MatchmakingBuildId: buildConfig.matchmakingBuildId

View File

@ -2,6 +2,7 @@ import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { Account } from "@/src/models/loginModel";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const logoutController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const account = await Account.findOne({ _id: accountId });

View File

@ -1,6 +1,6 @@
import { RequestHandler } from "express";
import { missionInventoryUpdate } from "@/src/services/inventoryService";
import { combineRewardAndLootInventory, getRewards } from "@/src/services/missionInventoryUpdateService ";
import { combineRewardAndLootInventory, getRewards } from "@/src/services/missionInventoryUpdateService";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { IMissionInventoryUpdateRequest } from "@/src/types/requestTypes";

View File

@ -0,0 +1,57 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { WeaponTypeInternal } from "@/src/services/itemDataService";
import { getInventory, updateCurrency, addWeapon, addMiscItems } from "@/src/services/inventoryService";
const modularWeaponTypes: Record<string, WeaponTypeInternal | "Hoverboards"> = {
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam": "LongGuns",
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary": "Pistols",
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam": "Pistols",
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun": "Pistols",
"/Lotus/Weapons/Ostron/Melee/LotusModularWeapon": "Melee",
"/Lotus/Weapons/Sentients/OperatorAmplifiers/OperatorAmpWeapon": "OperatorAmps",
"/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit": "Hoverboards"
};
interface IModularCraftRequest {
WeaponType: string;
Parts: string[];
}
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const modularWeaponCraftingController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const data: IModularCraftRequest = getJSONfromString(req.body.toString());
if (!(data.WeaponType in modularWeaponTypes)) {
throw new Error(`unknown modular weapon type: ${data.WeaponType}`);
}
const category = modularWeaponTypes[data.WeaponType];
// Give weapon
const weapon = await addWeapon(category, data.WeaponType, accountId, data.Parts);
// Remove credits
const currencyChanges = await updateCurrency(category == "Hoverboards" ? 5000 : 4000, false, accountId);
// Remove parts
const miscItemChanges = [];
for (const part of data.Parts) {
miscItemChanges.push({
ItemType: part,
ItemCount: -1
});
}
const inventory = await getInventory(accountId);
addMiscItems(inventory, miscItemChanges);
await inventory.save();
// Tell client what we did
res.json({
InventoryChanges: {
...currencyChanges,
[category]: [weapon],
MiscItems: miscItemChanges
}
});
};

View File

@ -0,0 +1,28 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
interface INameWeaponRequest {
ItemName: string;
}
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const nameWeaponController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const body = getJSONfromString(req.body.toString()) as INameWeaponRequest;
const item = inventory[req.query.Category as string as TEquipmentKey].find(
item => item._id.toString() == (req.query.ItemId as string)
)!;
if (body.ItemName != "") {
item.ItemName = body.ItemName;
} else {
item.ItemName = undefined;
}
await inventory.save();
res.json({
InventoryChanges: await updateCurrency("webui" in req.query ? 0 : 15, true, accountId)
});
};

View File

@ -1,9 +1,10 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { toPurchaseRequest } from "@/src/helpers/purchaseHelpers";
import { handlePurchase } from "@/src/services/purchaseService";
import { Request, Response } from "express";
export const purchaseController = async (req: Request, res: Response) => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const purchaseController: RequestHandler = async (req, res) => {
const purchaseRequest = toPurchaseRequest(JSON.parse(String(req.body)));
const accountId = await getAccountIdForRequest(req);
const response = await handlePurchase(purchaseRequest, accountId);

View File

@ -1,8 +1,9 @@
import { RequestHandler } from "express";
import { ISellRequest } from "@/src/types/sellTypes";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory, addMods } from "@/src/services/inventoryService";
import { getInventory, addMods, addRecipes } from "@/src/services/inventoryService";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const sellController: RequestHandler = async (req, res) => {
const payload: ISellRequest = JSON.parse(req.body.toString());
const accountId = await getAccountIdForRequest(req);
@ -39,8 +40,14 @@ export const sellController: RequestHandler = async (req, res) => {
});
}
if (payload.Items.Recipes) {
// TODO
// Note: sellItem.String is a uniqueName in this case
const recipeChanges = [];
for (const sellItem of payload.Items.Recipes) {
recipeChanges.push({
ItemType: sellItem.String,
ItemCount: sellItem.Count * -1
});
}
addRecipes(inventory, recipeChanges);
}
if (payload.Items.Upgrades) {
payload.Items.Upgrades.forEach(sellItem => {

View File

@ -3,6 +3,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
import { getPersonalRooms } from "@/src/services/personalRoomsService";
import { TBootLocation } from "@/src/types/shipTypes";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const setBootLocationController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const personalRooms = await getPersonalRooms(accountId);

View File

@ -2,6 +2,7 @@ import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory } from "@/src/services/inventoryService";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const setSupportedSyndicateController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);

View File

@ -0,0 +1,24 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory } from "@/src/services/inventoryService";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { WeaponTypeInternal } from "@/src/services/itemDataService";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const setWeaponSkillTreeController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const payload = getJSONfromString(req.body.toString()) as ISetWeaponSkillTreeRequest;
const item = inventory[req.query.Category as WeaponTypeInternal].find(
item => item._id.toString() == (req.query.ItemId as string)
)!;
item.SkillTree = payload.SkillTree;
await inventory.save();
res.end();
};
interface ISetWeaponSkillTreeRequest {
SkillTree: string;
}

View File

@ -8,6 +8,7 @@ interface IStartDojoRecipeRequest {
Revision: number;
}
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const startDojoRecipeController: RequestHandler = async (req, res) => {
const guild = await getGuildForRequest(req);
// At this point, we know that a member of the guild is making this request. Assuming they are allowed to start a build.

View File

@ -0,0 +1,15 @@
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getInventory } from "@/src/services/inventoryService";
import { IStepSequencer } from "@/src/types/inventoryTypes/inventoryTypes";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const stepSequencersController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const stepSequencer = JSON.parse(req.body.toString()) as IStepSequencer;
delete stepSequencer.ItemId;
const stepSequencerIndex = inventory.StepSequencers.push(stepSequencer);
const changedInventory = await inventory.save();
res.json(changedInventory.StepSequencers[stepSequencerIndex - 1]); // unsure about the expected response format, but it seems anything works.
};

View File

@ -3,6 +3,7 @@ import { syndicateSacrifice } from "@/src/services/inventoryService";
import { ISyndicateSacrifice } from "@/src/types/syndicateTypes";
import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const syndicateSacrificeController: RequestHandler = async (request, response) => {
const accountId = await getAccountIdForRequest(request);

View File

@ -4,6 +4,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
import { updateChallengeProgress } from "@/src/services/inventoryService";
import { IUpdateChallengeProgressRequest } from "@/src/types/requestTypes";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const updateChallengeProgressController: RequestHandler = async (req, res) => {
const payload: IUpdateChallengeProgressRequest = getJSONfromString(req.body.toString());
const accountId = await getAccountIdForRequest(req);

View File

@ -1,10 +1,11 @@
import { RequestHandler } from "express";
import { IUpgradesRequest } from "@/src/types/requestTypes";
import { FocusSchool } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { IGenericItemDatabase, IMiscItem, TGenericItemKey } from "@/src/types/inventoryTypes/inventoryTypes";
import { FocusSchool, IEquipmentDatabase, EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { IMiscItem, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
export const upgradesController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const payload = JSON.parse(req.body.toString()) as IUpgradesRequest;
@ -28,20 +29,20 @@ export const upgradesController: RequestHandler = async (req, res) => {
switch (operation.UpgradeRequirement) {
case "/Lotus/Types/Items/MiscItems/OrokinReactor":
case "/Lotus/Types/Items/MiscItems/OrokinCatalyst":
for (const item of inventory[payload.ItemCategory as TGenericItemKey] as IGenericItemDatabase[]) {
for (const item of inventory[payload.ItemCategory as TEquipmentKey] as IEquipmentDatabase[]) {
if (item._id.toString() == payload.ItemId.$oid) {
item.Features ??= 0;
item.Features |= 1;
item.Features |= EquipmentFeatures.DOUBLE_CAPACITY;
break;
}
}
break;
case "/Lotus/Types/Items/MiscItems/UtilityUnlocker":
case "/Lotus/Types/Items/MiscItems/WeaponUtilityUnlocker":
for (const item of inventory[payload.ItemCategory as TGenericItemKey] as IGenericItemDatabase[]) {
for (const item of inventory[payload.ItemCategory as TEquipmentKey] as IEquipmentDatabase[]) {
if (item._id.toString() == payload.ItemId.$oid) {
item.Features ??= 0;
item.Features |= 2;
item.Features |= EquipmentFeatures.UTILITY_SLOT;
break;
}
}
@ -49,10 +50,10 @@ export const upgradesController: RequestHandler = async (req, res) => {
case "/Lotus/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker":
case "/Lotus/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker":
case "/Lotus/Types/Items/MiscItems/WeaponMeleeArcaneUnlocker":
for (const item of inventory[payload.ItemCategory as TGenericItemKey] as IGenericItemDatabase[]) {
for (const item of inventory[payload.ItemCategory as TEquipmentKey] as IEquipmentDatabase[]) {
if (item._id.toString() == payload.ItemId.$oid) {
item.Features ??= 0;
item.Features |= 32;
item.Features |= EquipmentFeatures.ARCANE_SLOT;
break;
}
}
@ -61,7 +62,7 @@ export const upgradesController: RequestHandler = async (req, res) => {
case "/Lotus/Types/Items/MiscItems/FormaUmbra":
case "/Lotus/Types/Items/MiscItems/FormaAura":
case "/Lotus/Types/Items/MiscItems/FormaStance":
for (const item of inventory[payload.ItemCategory as TGenericItemKey] as IGenericItemDatabase[]) {
for (const item of inventory[payload.ItemCategory as TEquipmentKey] as IEquipmentDatabase[]) {
if (item._id.toString() == payload.ItemId.$oid) {
item.XP = 0;
setSlotPolarity(item, operation.PolarizeSlot, operation.PolarizeValue);
@ -72,7 +73,7 @@ export const upgradesController: RequestHandler = async (req, res) => {
}
break;
case "/Lotus/Types/Items/MiscItems/ModSlotUnlocker":
for (const item of inventory[payload.ItemCategory as TGenericItemKey] as IGenericItemDatabase[]) {
for (const item of inventory[payload.ItemCategory as TEquipmentKey] as IEquipmentDatabase[]) {
if (item._id.toString() == payload.ItemId.$oid) {
item.ModSlotPurchases ??= 0;
item.ModSlotPurchases += 1;
@ -87,7 +88,7 @@ export const upgradesController: RequestHandler = async (req, res) => {
}
break;
case "/Lotus/Types/Items/MiscItems/CustomizationSlotUnlocker":
for (const item of inventory[payload.ItemCategory as TGenericItemKey] as IGenericItemDatabase[]) {
for (const item of inventory[payload.ItemCategory as TEquipmentKey] as IEquipmentDatabase[]) {
if (item._id.toString() == payload.ItemId.$oid) {
item.CustomizationSlotPurchases ??= 0;
item.CustomizationSlotPurchases += 1;
@ -103,7 +104,7 @@ export const upgradesController: RequestHandler = async (req, res) => {
break;
case "":
console.assert(operation.OperationType == "UOT_SWAP_POLARITY");
for (const item of inventory[payload.ItemCategory as TGenericItemKey] as IGenericItemDatabase[]) {
for (const item of inventory[payload.ItemCategory as TEquipmentKey] as IEquipmentDatabase[]) {
if (item._id.toString() == payload.ItemId.$oid) {
for (let i = 0; i != operation.PolarityRemap.length; ++i) {
if (operation.PolarityRemap[i].Slot != i) {
@ -122,7 +123,7 @@ export const upgradesController: RequestHandler = async (req, res) => {
res.json({ InventoryChanges });
};
const setSlotPolarity = (item: IGenericItemDatabase, slot: number, polarity: FocusSchool): void => {
const setSlotPolarity = (item: IEquipmentDatabase, slot: number, polarity: FocusSchool): void => {
item.Polarity ??= [];
const entry = item.Polarity.find(entry => entry.Slot == slot);
if (entry) {

View File

@ -1,8 +1,8 @@
import { RequestHandler } from "express";
import configFile from "@/config.json";
import { config } from "@/src/services/configService";
const getConfigDataController: RequestHandler = (_req, res) => {
res.json(configFile);
res.json(config);
};
export { getConfigDataController };

View File

@ -1,7 +1,13 @@
import { RequestHandler } from "express";
import { MinItem, MinWeapon, warframes, items, getEnglishString } from "@/src/services/itemDataService";
import { MinItem, items, getEnglishString } from "@/src/services/itemDataService";
import badItems from "@/static/json/exclude-mods.json";
import { ExportArcanes, ExportWeapons } from "warframe-public-export-plus";
import {
ExportArcanes,
ExportGear,
ExportResources,
ExportWarframes,
ExportWeapons
} from "warframe-public-export-plus";
interface ListedItem {
uniqueName: string;
@ -20,6 +26,36 @@ function reduceItems(items: MinItem[]): ListedItem[] {
}
const getItemListsController: RequestHandler = (_req, res) => {
const weapons = [];
const miscitems = [];
for (const [uniqueName, item] of Object.entries(ExportWeapons)) {
if (item.productCategory !== "OperatorAmps") {
if (item.totalDamage !== 0) {
weapons.push({
uniqueName,
name: getEnglishString(item.name)
});
} else if (!item.excludeFromCodex) {
miscitems.push({
uniqueName: "MiscItems:" + uniqueName,
name: getEnglishString(item.name)
});
}
}
}
for (const [uniqueName, item] of Object.entries(ExportResources)) {
miscitems.push({
uniqueName: "MiscItems:" + uniqueName,
name: getEnglishString(item.name)
});
}
for (const [uniqueName, item] of Object.entries(ExportGear)) {
miscitems.push({
uniqueName: "Consumables:" + uniqueName,
name: getEnglishString(item.name)
});
}
const mods = reduceItems(items.filter(item => item.category == "Mods"));
for (const [uniqueName, arcane] of Object.entries(ExportArcanes)) {
mods.push({
@ -27,25 +63,18 @@ const getItemListsController: RequestHandler = (_req, res) => {
name: getEnglishString(arcane.name)
});
}
res.json({
warframes: reduceItems(warframes),
weapons: Object.entries(ExportWeapons)
.filter(([_uniqueName, weapon]) => weapon.productCategory !== "OperatorAmps" && weapon.totalDamage !== 0)
.map(([uniqueName, weapon]) => {
warframes: Object.entries(ExportWarframes)
.filter(([_uniqueName, warframe]) => warframe.productCategory == "Suits")
.map(([uniqueName, warframe]) => {
return {
uniqueName,
name: getEnglishString(weapon.name)
name: getEnglishString(warframe.name)
};
}),
miscitems: reduceItems(
items.filter(
item =>
item.category == "Misc" ||
item.category == "Resources" ||
item.category == "Fish" ||
((item as any).productCategory == "Pistols" && (item as MinWeapon).totalDamage == 0)
)
),
weapons,
miscitems,
mods,
badItems
});

View File

@ -1,16 +1,10 @@
import { RequestHandler } from "express";
import path from "path";
import fs from "fs";
const rootDir = path.join(__dirname, "../../..");
import { updateConfig } from "@/src/services/configService";
const updateConfigDataController: RequestHandler = (req) => {
const updateSettingsData = req.body;
fs.writeFile(path.join(rootDir, "config.json"), updateSettingsData, function(err:any) {
if(err) {
return console.log(err);
}
});
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const updateConfigDataController: RequestHandler = async (req, res) => {
await updateConfig(req.body.toString());
res.end();
};
export { updateConfigDataController };

View File

@ -6,6 +6,7 @@ import { config } from "@/src/services/configService";
import view from "@/static/fixed_responses/view.json";
import allScans from "@/static/fixed_responses/allScans.json";
// eslint-disable-next-line @typescript-eslint/no-misused-promises
const viewController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await Inventory.findOne({ accountOwnerId: accountId });

View File

@ -8,7 +8,6 @@ import {
IBooster,
IInventoryResponse,
ISlots,
IGenericItem,
IMailbox,
IDuviriInfo,
IPendingRecipe as IPendingRecipeDatabase,
@ -16,14 +15,13 @@ import {
ITypeCount,
IFocusXP,
IFocusUpgrades,
IGenericItem2,
ITypeXPItem,
IChallengeProgress,
IStepSequencer,
IAffiliation,
INotePacks,
ICompletedJobChain,
ISeasonChallengeHistory,
ISeasonChallenge,
IPlayerSkills,
ISettings,
IInfestedFoundry,
@ -37,18 +35,19 @@ import {
ITauntHistory,
IPeriodicMissionCompletionDatabase,
IPeriodicMissionCompletionResponse,
ILoreFragmentScan
ILoreFragmentScan,
IEvolutionProgress
} from "../../types/inventoryTypes/inventoryTypes";
import { IOid } from "../../types/commonTypes";
import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes";
import { IWeaponDatabase } from "@/src/types/inventoryTypes/weaponTypes";
import {
IAbilityOverride,
IColor,
IItemConfig,
IOperatorConfigClient,
IOperatorConfigDatabase,
IPolarity
IPolarity,
IEquipmentDatabase,
IOperatorConfigClient,
IArchonCrystalUpgrade
} from "@/src/types/inventoryTypes/commonInventoryTypes";
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
@ -163,14 +162,17 @@ const ItemConfigSchema = new Schema<IItemConfig>(
facial: colorSchema,
syancol: colorSchema,
Upgrades: [String],
Songs: [
{
m: String,
b: String,
p: String,
s: String
}
],
Songs: {
type: [
{
m: String,
b: String,
p: String,
s: String
}
],
default: undefined
},
Name: String,
AbilityOverride: abilityOverrideSchema,
PvpUpgrades: [String],
@ -185,8 +187,21 @@ ItemConfigSchema.set("toJSON", {
}
});
//TODO: migrate to one schema for weapons and suits.. and possibly others
const WeaponSchema = new Schema<IWeaponDatabase>(
const ArchonCrystalUpgradeSchema = new Schema<IArchonCrystalUpgrade>(
{
UpgradeType: String,
Color: String
},
{ _id: false }
);
ArchonCrystalUpgradeSchema.set("toJSON", {
transform(_document, returnedObject) {
delete returnedObject.__v;
}
});
const EquipmentSchema = new Schema<IEquipmentDatabase>(
{
ItemType: String,
Configs: [ItemConfigSchema],
@ -198,20 +213,26 @@ const WeaponSchema = new Schema<IWeaponDatabase>(
FocusLens: String,
ModSlotPurchases: Number,
CustomizationSlotPurchases: Number,
UpgradeType: Schema.Types.Mixed, //todo
UpgradeType: String,
UpgradeFingerprint: String,
ItemName: String,
ModularParts: [String],
UnlockLevel: Number
InfestationDate: Date,
InfestationDays: Number,
InfestationType: String,
ModularParts: { type: [String], default: undefined },
UnlockLevel: Number,
Expiry: Date,
SkillTree: String,
ArchonCrystalUpgrades: { type: [ArchonCrystalUpgradeSchema], default: undefined }
},
{ id: false }
);
WeaponSchema.virtual("ItemId").get(function () {
EquipmentSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
WeaponSchema.set("toJSON", {
EquipmentSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject) {
delete returnedObject._id;
@ -248,7 +269,7 @@ RawUpgrades.set("toJSON", {
});
//TODO: find out what this is
const upgrqadesSchema = new Schema(
const upgradesSchema = new Schema(
{
UpgradeFingerprint: String,
ItemType: String
@ -256,42 +277,11 @@ const upgrqadesSchema = new Schema(
{ id: false }
);
upgrqadesSchema.virtual("ItemId").get(function () {
upgradesSchema.virtual("ItemId").get(function () {
return toOid(this._id);
});
upgrqadesSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
//TODO: reduce weapon and suit schemas to one schema if reasonable
const suitSchema = new Schema<ISuitDatabase>(
{
ItemType: String,
Configs: [ItemConfigSchema],
UpgradeVer: Number,
XP: Number,
InfestationDate: Date,
Features: Number,
Polarity: [polaritySchema],
Polarized: Number,
ModSlotPurchases: Number,
CustomizationSlotPurchases: Number,
FocusLens: String,
UnlockLevel: Number
},
{ id: false }
);
suitSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
suitSchema.set("toJSON", {
upgradesSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject) {
delete returnedObject._id;
@ -321,33 +311,6 @@ FlavourItemSchema.set("toJSON", {
}
});
const GenericItemSchema = new Schema<IGenericItem>(
{
ItemType: String,
Configs: [ItemConfigSchema],
UpgradeVer: Number,
XP: Number,
Features: Number,
Polarity: [polaritySchema],
Polarized: Number,
ModSlotPurchases: Number,
CustomizationSlotPurchases: Number
},
{ id: false }
);
GenericItemSchema.virtual("ItemId").get(function () {
return { $oid: this._id.toString() } satisfies IOid;
});
GenericItemSchema.set("toJSON", {
virtuals: true,
transform(_document, returnedObject) {
delete returnedObject._id;
delete returnedObject.__v;
}
});
// "Mailbox": { "LastInboxId": { "$oid": "123456780000000000000000" } }
const MailboxSchema = new Schema<IMailbox>(
{
@ -384,30 +347,6 @@ DuviriInfoSchema.set("toJSON", {
}
});
// eslint-disable-next-line @typescript-eslint/no-unused-vars
const GenericItemSchema2 = new Schema<IGenericItem2>({
ItemType: String,
ItemName: String,
XP: Number,
UpgradeVer: Number, //this is probably __v
Features: Number,
Polarized: Number,
CustomizationSlotPurchases: Number,
ModSlotPurchases: Number,
FocusLens: String,
Expiry: Date, //TODO: needs conversion
Polarity: [polaritySchema],
Configs: [ItemConfigSchema],
ModularParts: [String],
SkillTree: String,
UpgradeType: String,
UpgradeFingerprint: String,
OffensiveUpgrade: String,
DefensiveUpgrade: String,
UpgradesExpiry: Date, //TODO: needs conversion
ArchonCrystalUpgrades: []
});
const TypeXPItemSchema = new Schema<ITypeXPItem>(
{
ItemType: String,
@ -475,7 +414,7 @@ const completedJobChainsSchema = new Schema<ICompletedJobChain>(
{ _id: false }
);
const seasonChallengeHistorySchema = new Schema<ISeasonChallengeHistory>(
const seasonChallengeHistorySchema = new Schema<ISeasonChallenge>(
{
challenge: String,
id: String
@ -515,16 +454,19 @@ const consumedSchuitsSchema = new Schema<IConsumedSuit>({
c: colorSchema
});
const infestedFoundrySchema = new Schema<IInfestedFoundry>({
Name: String,
Resources: [typeCountSchema],
Slots: Number,
XP: Number,
ConsumedSuits: [consumedSchuitsSchema],
InvigorationIndex: Number,
InvigorationSuitOfferings: [String],
InvigorationsApplied: Number
});
const infestedFoundrySchema = new Schema<IInfestedFoundry>(
{
Name: String,
Resources: { type: [typeCountSchema], default: undefined },
Slots: Number,
XP: Number,
ConsumedSuits: { type: [consumedSchuitsSchema], default: undefined },
InvigorationIndex: Number,
InvigorationSuitOfferings: { type: [String], default: undefined },
InvigorationsApplied: Number
},
{ _id: false }
);
const questProgressSchema = new Schema<IQuestProgress>({
c: Number,
@ -621,6 +563,15 @@ const loreFragmentScansSchema = new Schema<ILoreFragmentScan>(
{ _id: false }
);
const evolutionProgressSchema = new Schema<IEvolutionProgress>(
{
Progress: Number,
Rank: Number,
ItemType: String
},
{ _id: false }
);
const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
{
accountOwnerId: Schema.Types.ObjectId,
@ -696,31 +647,31 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//Non Upgrade Mods Example:I have 999 item WeaponElectricityDamageMod (only "ItemCount"+"ItemType")
RawUpgrades: [RawUpgrades],
//Upgrade Mods\Riven\Arcane Example:"UpgradeFingerprint"+"ItemType"+""
Upgrades: [upgrqadesSchema],
Upgrades: [upgradesSchema],
//Warframe
Suits: [suitSchema],
Suits: [EquipmentSchema],
//Primary Weapon
LongGuns: [WeaponSchema],
LongGuns: [EquipmentSchema],
//Secondary Weapon
Pistols: [WeaponSchema],
Pistols: [EquipmentSchema],
//Melee Weapon
Melee: [WeaponSchema],
Melee: [EquipmentSchema],
//Ability Weapon like Ultimate Mech\Excalibur\Ivara etc
SpecialItems: [GenericItemSchema],
SpecialItems: [EquipmentSchema],
//The Mandachord(Octavia) is a step sequencer
StepSequencers: [StepSequencersSchema],
//Sentinel(like Helios or modular)
Sentinels: [Schema.Types.Mixed],
Sentinels: [EquipmentSchema],
//Any /Sentinels/SentinelWeapons/ (like warframe weapon)
SentinelWeapons: [Schema.Types.Mixed],
SentinelWeapons: [EquipmentSchema],
//Modular Pets
MoaPets: [Schema.Types.Mixed],
MoaPets: [EquipmentSchema],
KubrowPetEggs: [Schema.Types.Mixed],
//Like PowerSuit Cat\Kubrow or etc Pets
KubrowPets: [Schema.Types.Mixed],
KubrowPets: [EquipmentSchema],
//Prints Cat(3 Prints)\Kubrow(2 Prints) Pets
KubrowPetPrints: [Schema.Types.Mixed],
@ -735,27 +686,27 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//to use add SummonItem to Consumables+EquippedGear
//Archwing need Suits+Melee+Guns
SpaceSuits: [GenericItemSchema],
SpaceMelee: [GenericItemSchema],
SpaceGuns: [Schema.Types.Mixed],
SpaceSuits: [EquipmentSchema],
SpaceMelee: [EquipmentSchema],
SpaceGuns: [EquipmentSchema],
ArchwingEnabled: Boolean,
//Mech need Suits+SpaceGuns+SpecialItem
MechSuits: [suitSchema],
MechSuits: [EquipmentSchema],
///Restoratives/HoverboardSummon (like Suit)
Hoverboards: [Schema.Types.Mixed],
Hoverboards: [EquipmentSchema],
//Use Operator\Drifter
UseAdultOperatorLoadout: Boolean,
//Operator\Drifter Weapon
OperatorAmps: [Schema.Types.Mixed],
OperatorAmps: [EquipmentSchema],
//Operator
OperatorLoadOuts: [operatorConfigSchema],
//Drifter
AdultOperatorLoadOuts: [operatorConfigSchema],
DrifterMelee: [GenericItemSchema],
DrifterGuns: [GenericItemSchema],
DrifterMelee: [EquipmentSchema],
DrifterGuns: [EquipmentSchema],
//ErsatzHorsePowerSuit
Horses: [GenericItemSchema],
Horses: [EquipmentSchema],
//LandingCraft like Liset
Ships: { type: [Schema.Types.ObjectId], ref: "Ships" },
@ -763,7 +714,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
ShipDecorations: [typeCountSchema],
//RailJack Setting(Mods,Skin,Weapon,etc)
CrewShipHarnesses: [Schema.Types.Mixed],
CrewShipHarnesses: [EquipmentSchema],
//Railjack/Components(https://warframe.fandom.com/wiki/Railjack/Components)
CrewShipRawSalvage: [Schema.Types.Mixed],
@ -790,7 +741,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
FlavourItems: [FlavourItemSchema],
//Lunaro Weapon
Scoops: [GenericItemSchema],
Scoops: [EquipmentSchema],
//Mastery Rank*(Need item XPInfo to rank up)
PlayerLevel: Number,
@ -907,7 +858,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
InvasionChainProgress: [Schema.Types.Mixed],
//https://warframe.fandom.com/wiki/Parazon
DataKnives: [GenericItemSchema],
DataKnives: [EquipmentSchema],
//CorpusLich or GrineerLich
NemesisAbandonedRewards: [String],
@ -940,7 +891,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//Progress+Rank+ItemType(ZarimanPumpShotgun)
//https://warframe.fandom.com/wiki/Incarnon
EvolutionProgress: [Schema.Types.Mixed],
EvolutionProgress: { type: [evolutionProgressSchema], default: undefined },
//Unknown and system
DuviriInfo: DuviriInfoSchema,
@ -950,7 +901,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
ChallengesFixVersion: Number,
PlayedParkourTutorial: Boolean,
SubscribedToEmailsPersonalized: Number,
LastInventorySync: Schema.Types.Mixed,
LastInventorySync: Schema.Types.Mixed, // this should be Schema.Types.ObjectId, but older inventories may break with that.
ActiveLandscapeTraps: [Schema.Types.Mixed],
RepVotes: [Schema.Types.Mixed],
LeagueTickets: [Schema.Types.Mixed],
@ -976,7 +927,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//Grustag three
DeathSquadable: Boolean
},
{ timestamps: { createdAt: "Created", updatedAt: "LastInventorySync" } }
{ timestamps: { createdAt: "Created" } }
);
inventorySchema.set("toJSON", {
@ -1000,25 +951,31 @@ inventorySchema.set("toJSON", {
// type overwrites for subdocuments/subdocument arrays
type InventoryDocumentProps = {
Suits: Types.DocumentArray<ISuitDatabase>;
LongGuns: Types.DocumentArray<IWeaponDatabase>;
Pistols: Types.DocumentArray<IWeaponDatabase>;
Melee: Types.DocumentArray<IWeaponDatabase>;
Suits: Types.DocumentArray<IEquipmentDatabase>;
LongGuns: Types.DocumentArray<IEquipmentDatabase>;
Pistols: Types.DocumentArray<IEquipmentDatabase>;
Melee: Types.DocumentArray<IEquipmentDatabase>;
OperatorAmps: Types.DocumentArray<IEquipmentDatabase>;
FlavourItems: Types.DocumentArray<IFlavourItem>;
RawUpgrades: Types.DocumentArray<IRawUpgrade>;
Upgrades: Types.DocumentArray<ICrewShipSalvagedWeaponSkin>;
MiscItems: Types.DocumentArray<IMiscItem>;
Boosters: Types.DocumentArray<IBooster>;
OperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>;
SpecialItems: Types.DocumentArray<IGenericItem>;
SpecialItems: Types.DocumentArray<IEquipmentDatabase>;
AdultOperatorLoadOuts: Types.DocumentArray<IOperatorConfigClient>; //TODO: this should still contain _id
MechSuits: Types.DocumentArray<ISuitDatabase>;
Scoops: Types.DocumentArray<IGenericItem>;
DataKnives: Types.DocumentArray<IGenericItem>;
DrifterMelee: Types.DocumentArray<IGenericItem>;
Sentinels: Types.DocumentArray<IWeaponDatabase>;
Horses: Types.DocumentArray<IGenericItem>;
MechSuits: Types.DocumentArray<IEquipmentDatabase>;
Scoops: Types.DocumentArray<IEquipmentDatabase>;
DataKnives: Types.DocumentArray<IEquipmentDatabase>;
DrifterMelee: Types.DocumentArray<IEquipmentDatabase>;
Sentinels: Types.DocumentArray<IEquipmentDatabase>;
Horses: Types.DocumentArray<IEquipmentDatabase>;
PendingRecipes: Types.DocumentArray<IPendingRecipeDatabase>;
SpaceSuits: Types.DocumentArray<IEquipmentDatabase>;
SpaceGuns: Types.DocumentArray<IEquipmentDatabase>;
SpaceMelee: Types.DocumentArray<IEquipmentDatabase>;
SentinelWeapons: Types.DocumentArray<IEquipmentDatabase>;
Hoverboards: Types.DocumentArray<IEquipmentDatabase>;
};
// eslint-disable-next-line @typescript-eslint/ban-types

View File

@ -1,5 +1,6 @@
import { IOid } from "@/src/types/commonTypes";
import { ILoadoutConfigDatabase, ILoadoutDatabase, IEquipmentSelection } from "@/src/types/saveLoadoutTypes";
import { IEquipmentSelection } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { ILoadoutConfigDatabase, ILoadoutDatabase } from "@/src/types/saveLoadoutTypes";
import { Model, Schema, Types, model } from "mongoose";
const oidSchema = new Schema<IOid>(

View File

@ -7,7 +7,8 @@ const placedDecosSchema = new Schema<IPlacedDecosDatabase>(
{
Type: String,
Pos: [Number],
Rot: [Number]
Rot: [Number],
Scale: Number
},
{ id: false }
);

View File

@ -1,124 +1,135 @@
import express from "express";
import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
import { artifactsController } from "../controllers/api/artifactsController";
import { checkDailyMissionBonusController } from "@/src/controllers/api/checkDailyMissionBonusController";
import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
import { createGuildController } from "@/src/controllers/api/createGuildController";
import { deleteSessionController } from "@/src/controllers/api/deleteSessionController";
import { dojoController } from "@/src/controllers/api/dojoController";
import { dronesController } from "@/src/controllers/api/dronesController";
import { evolveWeaponController } from "@/src/controllers/api/evolveWeaponController";
import { findSessionsController } from "@/src/controllers/api/findSessionsController";
import { focusController } from "@/src/controllers/api/focusController";
import { genericUpdateController } from "@/src/controllers/api/genericUpdateController";
import { getAllianceController } from "@/src/controllers/api/getAllianceController";
import { getCreditsController } from "@/src/controllers/api/getCreditsController";
import { getDailyDealStockLevelsController } from "@/src/controllers/api/getDailyDealStockLevelsController";
import { getFriendsController } from "@/src/controllers/api/getFriendsController";
import { getGuildController } from "@/src/controllers/api/getGuildController";
import { getGuildDojoController } from "@/src/controllers/api/getGuildDojoController";
import { getGuildLogController } from "../controllers/api/getGuildLogController";
import { getIgnoredUsersController } from "@/src/controllers/api/getIgnoredUsersController";
import { getNewRewardSeedController } from "@/src/controllers/api/getNewRewardSeedController";
import { getShipController } from "@/src/controllers/api/getShipController";
import { getVendorInfoController } from "@/src/controllers/api/getVendorInfoController";
import { guildTechController } from "../controllers/api/guildTechController";
import { hostSessionController } from "@/src/controllers/api/hostSessionController";
import { hubController } from "@/src/controllers/api/hubController";
import { hubInstancesController } from "@/src/controllers/api/hubInstancesController";
import { inboxController } from "@/src/controllers/api/inboxController";
import { infestedFoundryController } from "@/src/controllers/api/infestedFoundryController";
import { inventoryController } from "@/src/controllers/api/inventoryController";
import { inventorySlotsController } from "@/src/controllers/api/inventorySlotsController";
import { joinSessionController } from "@/src/controllers/api/joinSessionController";
import { loginController } from "@/src/controllers/api/loginController";
import { loginRewardsController } from "@/src/controllers/api/loginRewardsController";
import { logoutController } from "@/src/controllers/api/logoutController";
import { marketRecommendationsController } from "@/src/controllers/api/marketRecommendationsController";
import { missionInventoryUpdateController } from "@/src/controllers/api/missionInventoryUpdateController";
import { modularWeaponCraftingController } from "@/src/controllers/api/modularWeaponCraftingController";
import { modularWeaponSaleController } from "@/src/controllers/api/modularWeaponSaleController";
import { nameWeaponController } from "@/src/controllers/api/nameWeaponController";
import { purchaseController } from "@/src/controllers/api/purchaseController";
import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController";
import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController";
import { saveLoadoutController } from "@/src/controllers/api/saveLoadout";
import { sellController } from "@/src/controllers/api/sellController";
import { setActiveQuestController } from "@/src/controllers/api/setActiveQuestController";
import { setActiveShipController } from "@/src/controllers/api/setActiveShipController";
import { setBootLocationController } from "@/src/controllers/api/setBootLocationController";
import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
import { setWeaponSkillTreeController } from "../controllers/api/setWeaponSkillTreeController";
import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController";
import { startDojoRecipeController } from "@/src/controllers/api/startDojoRecipeController";
import { startRecipeController } from "@/src/controllers/api/startRecipeController";
import { stepSequencersController } from "@/src/controllers/api/stepSequencersController";
import { surveysController } from "@/src/controllers/api/surveysController";
import { syndicateSacrificeController } from "../controllers/api/syndicateSacrificeController";
import { trainingResultController } from "@/src/controllers/api/trainingResultController";
import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController";
import { updateSessionGetController, updateSessionPostController } from "@/src/controllers/api/updateSessionController";
import { joinSessionController } from "@/src/controllers/api/joinSessionController";
import { saveLoadoutController } from "@/src/controllers/api/saveLoadout";
import { trainingResultController } from "@/src/controllers/api/trainingResultController";
import { artifactsController } from "../controllers/api/artifactsController";
import express from "express";
import { setBootLocationController } from "@/src/controllers/api/setBootLocationController";
import { focusController } from "@/src/controllers/api/focusController";
import { inventorySlotsController } from "@/src/controllers/api/inventorySlotsController";
import { startRecipeController } from "@/src/controllers/api/startRecipeController";
import { claimCompletedRecipeController } from "@/src/controllers/api/claimCompletedRecipeController";
import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController";
import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
import { setActiveShipController } from "@/src/controllers/api/setActiveShipController";
import { updateThemeController } from "../controllers/api/updateThemeController";
import { getGuildController } from "@/src/controllers/api/getGuildController";
import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
import { createGuildController } from "@/src/controllers/api/createGuildController";
import { sellController } from "@/src/controllers/api/sellController";
import { upgradesController } from "@/src/controllers/api/upgradesController";
import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
import { getDailyDealStockLevelsController } from "@/src/controllers/api/getDailyDealStockLevelsController";
import { getGuildLogController } from "../controllers/api/getGuildLogController";
import { guildTechController } from "../controllers/api/guildTechController";
import { dojoController } from "@/src/controllers/api/dojoController";
import { getGuildDojoController } from "@/src/controllers/api/getGuildDojoController";
import { syndicateSacrificeController } from "../controllers/api/syndicateSacrificeController";
import { startDojoRecipeController } from "@/src/controllers/api/startDojoRecipeController";
import { queueDojoComponentDestructionController } from "@/src/controllers/api/queueDojoComponentDestructionController";
const apiRouter = express.Router();
// get
apiRouter.get("/inventory.php", inventoryController);
apiRouter.get("/getFriends.php", getFriendsController);
apiRouter.get("/marketRecommendations.php", marketRecommendationsController);
apiRouter.get("/marketSearchRecommendations.php", marketRecommendationsController);
apiRouter.get("/surveys.php", surveysController);
apiRouter.get("/loginRewards.php", loginRewardsController);
apiRouter.get("/checkDailyMissionBonus.php", checkDailyMissionBonusController);
apiRouter.get("/inbox.php", inboxController);
apiRouter.get("/getShip.php", getShipController);
apiRouter.get("/credits.php", getCreditsController);
apiRouter.get("/deleteSession.php", deleteSessionController);
apiRouter.get("/dojo", dojoController);
apiRouter.get("/drones.php", dronesController);
apiRouter.get("/getDailyDealStockLevels.php", getDailyDealStockLevelsController);
apiRouter.get("/getFriends.php", getFriendsController);
apiRouter.get("/getGuild.php", getGuildController);
apiRouter.get("/getGuildDojo.php", getGuildDojoController);
apiRouter.get("/getGuildLog.php", getGuildLogController);
apiRouter.get("/getIgnoredUsers.php", getIgnoredUsersController);
apiRouter.get("/getNewRewardSeed.php", getNewRewardSeedController);
apiRouter.get("/setActiveQuest.php", setActiveQuestController);
apiRouter.get("/updateSession.php", updateSessionGetController);
apiRouter.get("/credits.php", getCreditsController);
apiRouter.get("/hubInstances", hubInstancesController);
apiRouter.get("/getShip.php", getShipController);
apiRouter.get("/getVendorInfo.php", getVendorInfoController);
apiRouter.get("/hub", hubController);
apiRouter.get("/modularWeaponSale.php", modularWeaponSaleController);
apiRouter.get("/deleteSession.php", deleteSessionController);
apiRouter.get("/hubInstances", hubInstancesController);
apiRouter.get("/inbox.php", inboxController);
apiRouter.get("/inventory.php", inventoryController);
apiRouter.get("/loginRewards.php", loginRewardsController);
apiRouter.get("/logout.php", logoutController);
apiRouter.get("/setBootLocation.php", setBootLocationController);
apiRouter.get("/setActiveShip.php", setActiveShipController);
apiRouter.get("/getGuild.php", getGuildController);
apiRouter.get("/setSupportedSyndicate.php", setSupportedSyndicateController);
apiRouter.get("/getDailyDealStockLevels.php", getDailyDealStockLevelsController);
apiRouter.get("/getGuildLog.php", getGuildLogController);
apiRouter.get("/dojo", dojoController);
apiRouter.get("/getGuildDojo.php", getGuildDojoController);
apiRouter.get("/marketRecommendations.php", marketRecommendationsController);
apiRouter.get("/marketSearchRecommendations.php", marketRecommendationsController);
apiRouter.get("/modularWeaponSale.php", modularWeaponSaleController);
apiRouter.get("/queueDojoComponentDestruction.php", queueDojoComponentDestructionController);
apiRouter.get("/setActiveQuest.php", setActiveQuestController);
apiRouter.get("/setActiveShip.php", setActiveShipController);
apiRouter.get("/setBootLocation.php", setBootLocationController);
apiRouter.get("/setSupportedSyndicate.php", setSupportedSyndicateController);
apiRouter.get("/surveys.php", surveysController);
apiRouter.get("/updateSession.php", updateSessionGetController);
// post
// eslint-disable-next-line @typescript-eslint/no-misused-promises
apiRouter.post("/shipDecorations.php", shipDecorationsController);
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
apiRouter.post("/startRecipe.php", startRecipeController);
apiRouter.post("/inventorySlots.php", inventorySlotsController);
apiRouter.post("/focus.php", focusController);
apiRouter.post("/artifacts.php", artifactsController);
apiRouter.post("/findSessions.php", findSessionsController);
// eslint-disable-next-line @typescript-eslint/no-misused-promises
apiRouter.post("/purchase.php", purchaseController);
apiRouter.post("/login.php", loginController);
apiRouter.post("/getAlliance.php", getAllianceController);
apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController);
apiRouter.post("/hostSession.php", hostSessionController);
apiRouter.post("/updateSession.php", updateSessionPostController);
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
apiRouter.post("/genericUpdate.php", genericUpdateController);
apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
apiRouter.post("/joinSession.php", joinSessionController);
apiRouter.post("/saveLoadout.php", saveLoadoutController);
apiRouter.post("/trainingResult.php", trainingResultController);
apiRouter.post("/updateTheme.php", updateThemeController);
apiRouter.post("/addFriendImage.php", addFriendImageController);
apiRouter.post("/artifacts.php", artifactsController);
apiRouter.post("/claimCompletedRecipe.php", claimCompletedRecipeController);
apiRouter.post("/createGuild.php", createGuildController);
apiRouter.post("/sell.php", sellController);
apiRouter.post("/upgrades.php", upgradesController);
apiRouter.post("/evolveWeapon.php", evolveWeaponController);
apiRouter.post("/findSessions.php", findSessionsController);
apiRouter.post("/focus.php", focusController);
apiRouter.post("/genericUpdate.php", genericUpdateController);
apiRouter.post("/getAlliance.php", getAllianceController);
apiRouter.post("/guildTech.php", guildTechController);
apiRouter.post("/syndicateSacrifice.php", syndicateSacrificeController);
apiRouter.post("/hostSession.php", hostSessionController);
apiRouter.post("/infestedFoundry.php", infestedFoundryController);
apiRouter.post("/inventorySlots.php", inventorySlotsController);
apiRouter.post("/joinSession.php", joinSessionController);
apiRouter.post("/login.php", loginController);
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController);
apiRouter.post("/nameWeapon.php", nameWeaponController);
apiRouter.post("/purchase.php", purchaseController);
apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
apiRouter.post("/saveLoadout.php", saveLoadoutController);
apiRouter.post("/sell.php", sellController);
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
apiRouter.post("/setWeaponSkillTree.php", setWeaponSkillTreeController);
apiRouter.post("/shipDecorations.php", shipDecorationsController);
apiRouter.post("/startDojoRecipe.php", startDojoRecipeController);
apiRouter.post("/startRecipe.php", startRecipeController);
apiRouter.post("/stepSequencers.php", stepSequencersController);
apiRouter.post("/syndicateSacrifice.php", syndicateSacrificeController);
apiRouter.post("/trainingResult.php", trainingResultController);
apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController);
apiRouter.post("/updateSession.php", updateSessionPostController);
apiRouter.post("/updateTheme.php", updateThemeController);
apiRouter.post("/upgrades.php", upgradesController);
export { apiRouter };

View File

@ -16,6 +16,7 @@ cacheRouter.get(/^\/origin\/[a-zA-Z0-9]+\/[0-9]+\/H\.Cache\.bin.*$/, (_req, res)
res.sendFile(`static/data/H.Cache_${buildConfig.version}.bin`, { root: "./" });
});
// eslint-disable-next-line @typescript-eslint/no-misused-promises
cacheRouter.get(/\.bk2!/, async (req, res) => {
try {
const dir = req.path.substr(0, req.path.lastIndexOf("/"));

View File

@ -1,4 +1,22 @@
import rawConfig from "@/config.json";
import path from "path";
import fs from "fs";
import fsPromises from "fs/promises";
import { logger } from "@/src/utils/logger";
const rootDir = path.join(__dirname, "../..");
const repoDir = path.basename(rootDir) == "build" ? path.join(rootDir, "..") : rootDir;
const configPath = path.join(repoDir, "config.json");
export const config: IConfig = JSON.parse(fs.readFileSync(configPath, "utf-8"));
let amnesia = false;
fs.watchFile(configPath, () => {
if (amnesia) {
amnesia = false;
} else {
logger.info("Detected a change to config.json, reloading its contents.");
Object.assign(config, JSON.parse(fs.readFileSync(configPath, "utf-8")));
}
});
interface IConfig {
mongodbUrl: string;
@ -6,6 +24,7 @@ interface IConfig {
myAddress: string;
httpPort?: number;
httpsPort?: number;
myIrcAddresses?: string[];
autoCreateAccount?: boolean;
skipStoryModeChoice?: boolean;
skipTutorial?: boolean;
@ -26,4 +45,8 @@ interface ILoggerConfig {
level: string; // "fatal" | "error" | "warn" | "info" | "http" | "debug" | "trace";
}
export const config: IConfig = rawConfig;
export const updateConfig = async (data: string) => {
amnesia = true;
await fsPromises.writeFile(configPath, data);
Object.assign(config, JSON.parse(data));
};

View File

@ -2,9 +2,7 @@ import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
import new_inventory from "@/static/fixed_responses/postTutorialInventory.json";
import { config } from "@/src/services/configService";
import { Types } from "mongoose";
import { ISuitClient } from "@/src/types/inventoryTypes/SuitTypes";
import { SlotNames } from "@/src/types/purchaseTypes";
import { IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes";
import { SlotNames, IInventoryChanges } from "@/src/types/purchaseTypes";
import {
IChallengeProgress,
IConsumable,
@ -13,8 +11,9 @@ import {
IMiscItem,
IMission,
IRawUpgrade,
ISeasonChallengeHistory,
ITypeCount
ISeasonChallenge,
ITypeCount,
InventorySlot
} from "@/src/types/inventoryTypes/inventoryTypes";
import { IGenericUpdate } from "../types/genericUpdate";
import {
@ -24,8 +23,10 @@ import {
IUpdateChallengeProgressRequest
} from "../types/requestTypes";
import { logger } from "@/src/utils/logger";
import { WeaponTypeInternal, getExalted } from "@/src/services/itemDataService";
import { WeaponTypeInternal, getWeaponType, getExalted } from "@/src/services/itemDataService";
import { ISyndicateSacrifice, ISyndicateSacrificeResponse } from "../types/syndicateTypes";
import { IEquipmentClient } from "../types/inventoryTypes/commonInventoryTypes";
import { ExportRecipes, ExportResources } from "warframe-public-export-plus";
export const createInventory = async (
accountOwnerId: Types.ObjectId,
@ -65,6 +66,204 @@ export const getInventory = async (accountOwnerId: string) => {
return inventory;
};
export const addItem = async (
accountId: string,
typeName: string,
quantity: number = 1
): Promise<{ InventoryChanges: IInventoryChanges }> => {
// Strict typing
if (typeName in ExportRecipes) {
const inventory = await getInventory(accountId);
const recipeChanges = [
{
ItemType: typeName,
ItemCount: quantity
} satisfies ITypeCount
];
addRecipes(inventory, recipeChanges);
await inventory.save();
return {
InventoryChanges: {
Recipes: recipeChanges
}
};
}
if (typeName in ExportResources) {
const inventory = await getInventory(accountId);
const miscItemChanges = [
{
ItemType: typeName,
ItemCount: quantity
} satisfies IMiscItem
];
addMiscItems(inventory, miscItemChanges);
await inventory.save();
return {
InventoryChanges: {
MiscItems: miscItemChanges
}
};
}
// Path-based duck typing
switch (typeName.substr(1).split("/")[1]) {
case "Powersuits":
switch (typeName.substr(1).split("/")[2]) {
default: {
const suit = await addPowerSuit(typeName, accountId);
await updateSlots(accountId, InventorySlot.SUITS, 0, 1);
return {
InventoryChanges: {
SuitBin: {
count: 1,
platinum: 0,
Slots: -1
},
Suits: [suit]
}
};
}
case "Archwing": {
const spaceSuit = await addSpaceSuit(typeName, accountId);
await updateSlots(accountId, InventorySlot.SPACESUITS, 0, 1);
return {
InventoryChanges: {
SpaceSuitBin: {
count: 1,
platinum: 0,
Slots: -1
},
SpaceSuits: [spaceSuit]
}
};
}
case "EntratiMech": {
const mechSuit = await addMechSuit(typeName, accountId);
await updateSlots(accountId, InventorySlot.MECHSUITS, 0, 1);
return {
InventoryChanges: {
MechBin: {
count: 1,
platinum: 0,
Slots: -1
},
MechSuits: [mechSuit]
}
};
}
}
break;
case "Weapons":
const weaponType = getWeaponType(typeName);
const weapon = await addWeapon(weaponType, typeName, accountId);
await updateSlots(accountId, InventorySlot.WEAPONS, 0, 1);
return {
InventoryChanges: {
WeaponBin: { count: 1, platinum: 0, Slots: -1 },
[weaponType]: [weapon]
}
};
case "Interface":
return {
InventoryChanges: {
FlavourItems: [await addCustomization(typeName, accountId)]
}
};
case "Objects": {
// /Lotus/Objects/Tenno/Props/TnoLisetTextProjector (Note Beacon)
const inventory = await getInventory(accountId);
const changes = [
{
ItemType: typeName,
ItemCount: quantity
} satisfies IMiscItem
];
addShipDecorations(inventory, changes);
await inventory.save();
return {
InventoryChanges: {
ShipDecorations: changes
}
};
}
case "Types":
switch (typeName.substr(1).split("/")[2]) {
case "AvatarImages":
case "SuitCustomizations":
return {
InventoryChanges: {
FlavourItems: [await addCustomization(typeName, accountId)]
}
};
case "Sentinels":
// TOOD: Sentinels should also grant their DefaultUpgrades & SentinelWeapon.
const sentinel = await addSentinel(typeName, accountId);
await updateSlots(accountId, InventorySlot.SENTINELS, 0, 1);
return {
InventoryChanges: {
SentinelBin: { count: 1, platinum: 0, Slots: -1 },
Sentinels: [sentinel]
}
};
case "Items": {
switch (typeName.substr(1).split("/")[3]) {
case "ShipDecos": {
const inventory = await getInventory(accountId);
const changes = [
{
ItemType: typeName,
ItemCount: quantity
} satisfies IMiscItem
];
addShipDecorations(inventory, changes);
await inventory.save();
return {
InventoryChanges: {
ShipDecorations: changes
}
};
}
default: {
const inventory = await getInventory(accountId);
const miscItemChanges = [
{
ItemType: typeName,
ItemCount: quantity
} satisfies IMiscItem
];
addMiscItems(inventory, miscItemChanges);
await inventory.save();
return {
InventoryChanges: {
MiscItems: miscItemChanges
}
};
}
}
}
case "Restoratives": // Codex Scanner, Remote Observer, Starburst
const inventory = await getInventory(accountId);
const consumablesChanges = [
{
ItemType: typeName,
ItemCount: quantity
} satisfies IConsumable
];
addConsumables(inventory, consumablesChanges);
await inventory.save();
return {
InventoryChanges: {
Consumables: consumablesChanges
}
};
}
break;
}
const errorMessage = `unable to add item: ${typeName}`;
logger.error(errorMessage);
throw new Error(errorMessage);
};
//TODO: maybe genericMethod for all the add methods, they share a lot of logic
export const addSentinel = async (sentinelName: string, accountId: string) => {
const inventory = await getInventory(accountId);
@ -73,7 +272,7 @@ export const addSentinel = async (sentinelName: string, accountId: string) => {
return changedInventory.Sentinels[sentinelIndex - 1].toJSON();
};
export const addPowerSuit = async (powersuitName: string, accountId: string): Promise<ISuitClient> => {
export const addPowerSuit = async (powersuitName: string, accountId: string): Promise<IEquipmentClient> => {
const specialItems = getExalted(powersuitName);
if (specialItems != false) {
for await (const specialItem of specialItems) {
@ -112,6 +311,13 @@ export const addSpecialItem = async (itemName: string, accountId: string) => {
return changedInventory.SpecialItems[specialItemIndex - 1].toJSON();
};
export const addSpaceSuit = async (spacesuitName: string, accountId: string) => {
const inventory = await getInventory(accountId);
const suitIndex = inventory.SpaceSuits.push({ ItemType: spacesuitName, Configs: [], UpgradeVer: 101, XP: 0 });
const changedInventory = await inventory.save();
return changedInventory.SpaceSuits[suitIndex - 1].toJSON();
};
export const updateSlots = async (accountId: string, slotName: SlotNames, slotAmount: number, extraAmount: number) => {
const inventory = await getInventory(accountId);
@ -219,26 +425,19 @@ export const syndicateSacrifice = async (
};
export const addWeapon = async (
weaponType: WeaponTypeInternal,
weaponType: WeaponTypeInternal | "Hoverboards",
weaponName: string,
accountId: string
): Promise<IWeaponClient> => {
accountId: string,
modularParts: string[] | undefined = undefined
): Promise<IEquipmentClient> => {
const inventory = await getInventory(accountId);
let weaponIndex;
switch (weaponType) {
case "LongGuns":
weaponIndex = inventory.LongGuns.push({ ItemType: weaponName, Configs: [], XP: 0 });
break;
case "Pistols":
weaponIndex = inventory.Pistols.push({ ItemType: weaponName, Configs: [], XP: 0 });
break;
case "Melee":
weaponIndex = inventory.Melee.push({ ItemType: weaponName, Configs: [], XP: 0 });
break;
default:
throw new Error("unknown weapon type: " + weaponType);
}
const weaponIndex = inventory[weaponType].push({
ItemType: weaponName,
Configs: [],
XP: 0,
ModularParts: modularParts
});
const changedInventory = await inventory.save();
return changedInventory[weaponType][weaponIndex - 1].toJSON();
@ -254,7 +453,7 @@ export const addCustomization = async (customizatonName: string, accountId: stri
const addGearExpByCategory = (
inventory: IInventoryDatabaseDocument,
gearArray: ISuitClient[] | IWeaponClient[] | undefined,
gearArray: IEquipmentClient[] | undefined,
categoryName: "Pistols" | "LongGuns" | "Melee" | "Suits"
) => {
const category = inventory[categoryName];
@ -300,6 +499,21 @@ export const addMiscItems = (inventory: IInventoryDatabaseDocument, itemsArray:
});
};
export const addShipDecorations = (inventory: IInventoryDatabaseDocument, itemsArray: IConsumable[] | undefined) => {
const { ShipDecorations } = inventory;
itemsArray?.forEach(({ ItemCount, ItemType }) => {
const itemIndex = ShipDecorations.findIndex(miscItem => miscItem.ItemType === ItemType);
if (itemIndex !== -1) {
ShipDecorations[itemIndex].ItemCount += ItemCount;
inventory.markModified(`ShipDecorations.${itemIndex}.ItemCount`);
} else {
ShipDecorations.push({ ItemCount, ItemType });
}
});
};
export const addConsumables = (inventory: IInventoryDatabaseDocument, itemsArray: IConsumable[] | undefined) => {
const { Consumables } = inventory;
@ -355,7 +569,7 @@ export const updateChallengeProgress = async (challenges: IUpdateChallengeProgre
export const addSeasonalChallengeHistory = (
inventory: IInventoryDatabaseDocument,
itemsArray: ISeasonChallengeHistory[] | undefined
itemsArray: ISeasonChallenge[] | undefined
) => {
const category = inventory.SeasonChallengeHistory;
@ -431,6 +645,22 @@ export const missionInventoryUpdate = async (data: IMissionInventoryUpdateReques
// Gear XP
gearKeys.forEach(key => addGearExpByCategory(inventory, data[key], key));
// Incarnon Challenges
if (data.EvolutionProgress) {
for (const evoProgress of data.EvolutionProgress) {
const entry = inventory.EvolutionProgress
? inventory.EvolutionProgress.find(entry => entry.ItemType == evoProgress.ItemType)
: undefined;
if (entry) {
entry.Progress = evoProgress.Progress;
entry.Rank = evoProgress.Rank;
} else {
inventory.EvolutionProgress ??= [];
inventory.EvolutionProgress.push(evoProgress);
}
}
}
// other
addMods(inventory, RawUpgrades);
addMiscItems(inventory, MiscItems);

View File

@ -1,23 +1,20 @@
import { getIndexAfter } from "@/src/helpers/stringHelpers";
import { logger } from "@/src/utils/logger";
import Items, { Buildable, Category, MinimalItem, Warframe, Weapon } from "warframe-items";
import Items, { Category, MinimalItem, Warframe, Weapon } from "warframe-items";
import badItems from "@/static/json/exclude-mods.json";
import { dict_en, ExportWarframes, ExportWeapons, IPowersuit } from "warframe-public-export-plus";
import {
dict_en,
ExportRecipes,
ExportWarframes,
ExportWeapons,
IPowersuit,
IRecipe
} from "warframe-public-export-plus";
export type MinWarframe = Omit<Warframe, "patchlogs">;
export type MinWeapon = Omit<Weapon, "patchlogs">;
export type MinItem = Omit<MinimalItem, "patchlogs">;
export const warframes: MinWarframe[] = Array.from(new Items({ category: ["Warframes"] }) as Warframe[])
.filter(item => {
return item.uniqueName.substring(0, 30) != "/Lotus/Powersuits/EntratiMech/";
})
.map(item => {
const next = { ...item };
delete next.patchlogs;
return next;
});
export type WeaponTypeInternal =
| "LongGuns"
| "Pistols"
@ -100,13 +97,8 @@ export const blueprintNames = Object.fromEntries(
.map(name => [name, craftNames[name]])
);
const buildables = items.filter(item => !!(item as Buildable).components);
export const getItemByBlueprint = (uniqueName: string): (MinItem & Buildable) | undefined => {
const item = buildables.find(item =>
(item as Buildable).components?.find(component => component.uniqueName === uniqueName)
);
return item;
export const getRecipe = (uniqueName: string): IRecipe | undefined => {
return ExportRecipes[uniqueName];
};
export const getExalted = (uniqueName: string) => {

View File

@ -174,7 +174,7 @@ const itemCheck = (
};
for (const key of Object.keys(rewardCheck) as IInventoryFieldType[]) {
if (rewardCheck[key]) {
addRewardResponse(InventoryChanges, MissionRewards, name, rewardCheck[key]!, key);
addRewardResponse(InventoryChanges, MissionRewards, name, rewardCheck[key], key);
return true;
}
}

View File

@ -1,23 +1,9 @@
import { parseSlotPurchaseName } from "@/src/helpers/purchaseHelpers";
import { getWeaponType } from "@/src/services/itemDataService";
import { getSubstringFromKeyword } from "@/src/helpers/stringHelpers";
import {
addBooster,
addConsumables,
addCustomization,
addMechSuit,
addMiscItems,
addPowerSuit,
addRecipes,
addSentinel,
addWeapon,
getInventory,
updateCurrency,
updateSlots
} from "@/src/services/inventoryService";
import { IConsumable, IMiscItem, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
import { IPurchaseRequest, IPurchaseResponse, SlotNameToInventoryName, SlotPurchase } from "@/src/types/purchaseTypes";
import { addItem, addBooster, updateCurrency, updateSlots } from "@/src/services/inventoryService";
import { IPurchaseRequest, SlotPurchase, IInventoryChanges, IBinChanges } from "@/src/types/purchaseTypes";
import { logger } from "@/src/utils/logger";
import { ExportBundles, TRarity } from "warframe-public-export-plus";
export const getStoreItemCategory = (storeItem: string) => {
const storeItemString = getSubstringFromKeyword(storeItem, "StoreItems/");
@ -36,38 +22,15 @@ export const getStoreItemTypesCategory = (typesItem: string) => {
export const handlePurchase = async (purchaseRequest: IPurchaseRequest, accountId: string) => {
logger.debug("purchase request", purchaseRequest);
const storeCategory = getStoreItemCategory(purchaseRequest.PurchaseParams.StoreItem);
const internalName = purchaseRequest.PurchaseParams.StoreItem.replace("/StoreItems", "");
logger.debug(`store category ${storeCategory}`);
let inventoryChanges;
switch (storeCategory) {
case "Powersuits":
inventoryChanges = await handlePowersuitPurchase(internalName, accountId);
break;
case "Weapons":
inventoryChanges = await handleWeaponsPurchase(internalName, accountId);
break;
case "Types":
inventoryChanges = await handleTypesPurchase(
internalName,
accountId,
purchaseRequest.PurchaseParams.Quantity
);
break;
case "Boosters":
inventoryChanges = await handleBoostersPurchase(internalName, accountId);
break;
case "Interface":
inventoryChanges = await handleCustomizationPurchase(internalName, accountId);
break;
default:
const errorMessage = `unknown store category: ${storeCategory} not implemented or new`;
logger.error(errorMessage);
throw new Error(errorMessage);
}
const purchaseResponse = await handleStoreItemAcquisition(
purchaseRequest.PurchaseParams.StoreItem,
accountId,
purchaseRequest.PurchaseParams.Quantity,
"COMMON"
);
if (!inventoryChanges) throw new Error("purchase response was undefined");
if (!purchaseResponse) throw new Error("purchase response was undefined");
const currencyChanges = await updateCurrency(
purchaseRequest.PurchaseParams.ExpectedPrice,
@ -75,12 +38,82 @@ export const handlePurchase = async (purchaseRequest: IPurchaseRequest, accountI
accountId
);
inventoryChanges.InventoryChanges = {
purchaseResponse.InventoryChanges = {
...currencyChanges,
...inventoryChanges.InventoryChanges
...purchaseResponse.InventoryChanges
};
return inventoryChanges;
return purchaseResponse;
};
const addInventoryChanges = (InventoryChanges: IInventoryChanges, delta: IInventoryChanges): void => {
for (const key in delta) {
if (!(key in InventoryChanges)) {
InventoryChanges[key] = delta[key];
} else if (Array.isArray(delta[key])) {
const left = InventoryChanges[key] as object[];
const right = delta[key] as object[];
for (const item of right) {
left.push(item);
}
} else {
console.assert(key.substring(-3) == "Bin");
const left = InventoryChanges[key] as IBinChanges;
const right = delta[key] as IBinChanges;
left.count += right.count;
left.platinum += right.platinum;
left.Slots += right.Slots;
if (right.Extra) {
left.Extra ??= 0;
left.Extra += right.Extra;
}
}
}
};
const handleStoreItemAcquisition = async (
storeItemName: string,
accountId: string,
quantity: number,
durability: TRarity
): Promise<{ InventoryChanges: IInventoryChanges }> => {
let purchaseResponse = {
InventoryChanges: {}
};
logger.debug(`handling acquision of ${storeItemName}`);
if (storeItemName in ExportBundles) {
const bundle = ExportBundles[storeItemName];
logger.debug("acquiring bundle", bundle);
for (const component of bundle.components) {
addInventoryChanges(
purchaseResponse.InventoryChanges,
(
await handleStoreItemAcquisition(
component.typeName,
accountId,
component.purchaseQuantity,
component.durability
)
).InventoryChanges
);
}
} else {
const storeCategory = getStoreItemCategory(storeItemName);
const internalName = storeItemName.replace("/StoreItems", "");
logger.debug(`store category ${storeCategory}`);
switch (storeCategory) {
default:
purchaseResponse = await addItem(accountId, internalName);
break;
case "Types":
purchaseResponse = await handleTypesPurchase(internalName, accountId, quantity);
break;
case "Boosters":
purchaseResponse = await handleBoostersPurchase(internalName, accountId, durability);
break;
}
}
return purchaseResponse;
};
export const slotPurchaseNameToSlotName: SlotPurchase = {
@ -100,7 +133,10 @@ export const slotPurchaseNameToSlotName: SlotPurchase = {
// // new slot above base = extra + 1 and slots +1
// // new frame = slots -1
// // number of frames = extra - slots + 2
const handleSlotPurchase = async (slotPurchaseNameFull: string, accountId: string) => {
const handleSlotPurchase = async (
slotPurchaseNameFull: string,
accountId: string
): Promise<{ InventoryChanges: IInventoryChanges }> => {
logger.debug(`slot name ${slotPurchaseNameFull}`);
const slotPurchaseName = parseSlotPurchaseName(
slotPurchaseNameFull.substring(slotPurchaseNameFull.lastIndexOf("/") + 1)
@ -126,102 +162,22 @@ const handleSlotPurchase = async (slotPurchaseNameFull: string, accountId: strin
};
};
const handleWeaponsPurchase = async (weaponName: string, accountId: string) => {
const weaponType = getWeaponType(weaponName);
const addedWeapon = await addWeapon(weaponType, weaponName, accountId);
await updateSlots(accountId, SlotNameToInventoryName.WEAPON, 0, 1);
return {
InventoryChanges: {
WeaponBin: { count: 1, platinum: 0, Slots: -1 },
[weaponType]: [addedWeapon]
}
} as IPurchaseResponse;
};
const handlePowersuitPurchase = async (powersuitName: string, accountId: string) => {
if (powersuitName.includes("EntratiMech")) {
const mechSuit = await addMechSuit(powersuitName, accountId);
await updateSlots(accountId, SlotNameToInventoryName.MECHSUIT, 0, 1);
logger.debug("mech suit", mechSuit);
return {
InventoryChanges: {
MechBin: {
count: 1,
platinum: 0,
Slots: -1
},
MechSuits: [mechSuit]
}
} as IPurchaseResponse;
}
const suit = await addPowerSuit(powersuitName, accountId);
await updateSlots(accountId, SlotNameToInventoryName.SUIT, 0, 1);
return {
InventoryChanges: {
SuitBin: {
count: 1,
platinum: 0,
Slots: -1
},
Suits: [suit]
}
};
};
//TODO: change to getInventory, apply changes then save at the end
const handleTypesPurchase = async (typesName: string, accountId: string, quantity: number) => {
const handleTypesPurchase = async (
typesName: string,
accountId: string,
quantity: number
): Promise<{ InventoryChanges: IInventoryChanges }> => {
const typeCategory = getStoreItemTypesCategory(typesName);
logger.debug(`type category ${typeCategory}`);
switch (typeCategory) {
case "AvatarImages":
case "SuitCustomizations":
return await handleCustomizationPurchase(typesName, accountId);
case "Sentinels":
return await handleSentinelPurchase(typesName, accountId);
default:
return await addItem(accountId, typesName, quantity);
case "SlotItems":
return await handleSlotPurchase(typesName, accountId);
case "Items":
return await handleMiscItemPurchase(typesName, accountId, quantity);
case "Recipes":
case "Consumables": // Blueprints for Ciphers, Antitoxins
return await handleRecipesPurchase(typesName, accountId, quantity);
case "Restoratives": // Codex Scanner, Remote Observer, Starburst
return await handleRestorativesPurchase(typesName, accountId, quantity);
break;
default:
throw new Error(`unknown Types category: ${typeCategory} not implemented or new`);
}
};
const handleSentinelPurchase = async (sentinelName: string, accountId: string) => {
const sentinel = await addSentinel(sentinelName, accountId);
await updateSlots(accountId, SlotNameToInventoryName.SENTINEL, 0, 1);
return {
InventoryChanges: {
SentinelBin: { count: 1, platinum: 0, Slots: -1 },
Sentinels: [sentinel]
}
};
};
const handleCustomizationPurchase = async (customizationName: string, accountId: string) => {
const customization = await addCustomization(customizationName, accountId);
return {
InventoryChanges: {
FlavourItems: [customization]
}
};
};
const boosterCollection = [
"/Lotus/Types/Boosters/ResourceAmountBooster",
"/Lotus/Types/Boosters/AffinityBooster",
@ -229,15 +185,25 @@ const boosterCollection = [
"/Lotus/Types/Boosters/CreditBooster"
];
const handleBoostersPurchase = async (boosterStoreName: string, accountId: string) => {
const match = boosterStoreName.match(/(\d+)Day/);
if (!match) return;
const boosterDuration: Record<TRarity, number> = {
COMMON: 3 * 86400,
UNCOMMON: 7 * 86400,
RARE: 30 * 86400,
LEGENDARY: 90 * 86400
};
const extractedDigit = Number(match[1]);
const ItemType = boosterCollection.find(i =>
boosterStoreName.includes(i.split("/").pop()!.replace("Booster", ""))
)!;
const ExpiryDate = extractedDigit * 86400;
const handleBoostersPurchase = async (
boosterStoreName: string,
accountId: string,
durability: TRarity
): Promise<{ InventoryChanges: IInventoryChanges }> => {
const ItemType = boosterStoreName.replace("StoreItem", "");
if (!boosterCollection.find(x => x == ItemType)) {
logger.error(`unknown booster type: ${ItemType}`);
return { InventoryChanges: {} };
}
const ExpiryDate = boosterDuration[durability];
await addBooster(ItemType, ExpiryDate, accountId);
@ -247,54 +213,3 @@ const handleBoostersPurchase = async (boosterStoreName: string, accountId: strin
}
};
};
const handleMiscItemPurchase = async (uniqueName: string, accountId: string, quantity: number) => {
const inventory = await getInventory(accountId);
const miscItemChanges = [
{
ItemType: uniqueName,
ItemCount: quantity
} satisfies IMiscItem
];
addMiscItems(inventory, miscItemChanges);
await inventory.save();
return {
InventoryChanges: {
MiscItems: miscItemChanges
}
};
};
const handleRecipesPurchase = async (uniqueName: string, accountId: string, quantity: number) => {
const inventory = await getInventory(accountId);
const recipeChanges = [
{
ItemType: uniqueName,
ItemCount: quantity
} satisfies ITypeCount
];
addRecipes(inventory, recipeChanges);
await inventory.save();
return {
InventoryChanges: {
Recipes: recipeChanges
}
};
};
const handleRestorativesPurchase = async (uniqueName: string, accountId: string, quantity: number) => {
const inventory = await getInventory(accountId);
const consumablesChanges = [
{
ItemType: uniqueName,
ItemCount: quantity
} satisfies IConsumable
];
addConsumables(inventory, consumablesChanges);
await inventory.save();
return {
InventoryChanges: {
Consumables: consumablesChanges
}
};
};

View File

@ -1,65 +1,30 @@
import { unixTimesInMs } from "@/src/constants/timeConstants";
import { getInventory } from "@/src/services/inventoryService";
import { getItemByBlueprint } from "@/src/services/itemDataService";
import { addMiscItems, getInventory, updateCurrency } from "@/src/services/inventoryService";
import { getRecipe } from "@/src/services/itemDataService";
import { logger } from "@/src/utils/logger";
import { Types } from "mongoose";
export interface IResource {
uniqueName: string;
count: number;
}
// export const updateResources = async (accountId: string, components: IResource[]) => {
// const inventory = await getInventory(accountId);
// for (const component of components) {
// const category = getItemCategoryByUniqueName(component.uniqueName) as keyof typeof inventory;
// //validate category
// console.log(component.uniqueName);
// console.log("cate", category);
// const invItem = inventory[category];
// console.log("invItem", invItem);
// inventory["MiscItems"];
// }
// };
export const startRecipe = async (recipeName: string, accountId: string) => {
const recipe = getItemByBlueprint(recipeName);
const recipe = getRecipe(recipeName);
if (!recipe) {
logger.error(`unknown recipe ${recipeName}`);
throw new Error(`unknown recipe ${recipeName}`);
}
const componentsNeeded = recipe.components?.map(component => ({
uniqueName: component.uniqueName,
count: component.itemCount
await updateCurrency(recipe.buildPrice, false, accountId);
const ingredientsInverse = recipe.ingredients.map(component => ({
ItemType: component.ItemType,
ItemCount: component.ItemCount * -1
}));
if (!componentsNeeded) {
logger.error(`recipe ${recipeName} has no components`);
throw new Error(`recipe ${recipeName} has no components`);
}
const inventory = await getInventory(accountId);
addMiscItems(inventory, ingredientsInverse);
//TODO: consume components used
//await updateResources(accountId, componentsNeeded);
//might be redundant
if (recipe.consumeOnBuild) {
//consume
}
if (!recipe.buildTime) {
logger.error(`recipe ${recipeName} has no build time`);
throw new Error(`recipe ${recipeName} has no build time`);
}
//buildtime is in seconds
const completionDate = new Date(Date.now() + recipe.buildTime * unixTimesInMs.second);
const inventory = await getInventory(accountId);
inventory.PendingRecipes.push({
ItemType: recipeName,
CompletionDate: completionDate,

View File

@ -132,7 +132,19 @@ export const handleInventoryItemConfigChange = async (
case "DataKnives":
case "DrifterMelee":
case "Sentinels":
case "Horses": {
case "Horses":
case "OperatorAmps":
case "SentinelWeapons":
case "KubrowPets":
case "SpaceSuits":
case "SpaceGuns":
case "SpaceMelee":
case "SpecialItems":
case "MoaPets":
case "Hoverboards":
case "MechSuits":
case "CrewShipHarnesses":
case "CrewShips": {
logger.debug(`general Item config saved of type ${equipmentName}`, { config: equipment });
const itemEntries = equipment as IItemEntry;
@ -159,21 +171,13 @@ export const handleInventoryItemConfigChange = async (
inventory.EquippedGear = equipment as string[];
break;
}
case "UseAdultOperatorLoadout": {
inventory.UseAdultOperatorLoadout = equipment as boolean;
break;
}
default: {
logger.error(`category not implemented: ${equipmentName}`, { config: equipment });
}
//case "OperatorAmps":
// case "SentinelWeapons":
// case "KubrowPets":
// case "SpaceSuits":
// case "SpaceGuns":
// case "SpaceMelee":
// case "SpecialItems":
// case "MoaPets":
// case "Hoverboards":
// case "MechSuits":
// case "CrewShipHarnesses":
// case "CrewShips":
//case "KahlLoadOuts": not sure yet how to handle kahl: it is not sent in inventory
}
}

View File

@ -6,6 +6,7 @@ import {
IShipDecorationsRequest,
IShipDecorationsResponse
} from "@/src/types/shipTypes";
import { logger } from "@/src/utils/logger";
import { Types } from "mongoose";
export const setShipCustomizations = async (shipCustomization: ISetShipCustomizationsRequest) => {
@ -37,12 +38,74 @@ export const handleSetShipDecorations = async (
const rooms = placedDecoration.IsApartment ? personalRooms.Apartment.Rooms : personalRooms.Ship.Rooms;
const room = rooms.find(room => room.Name === placedDecoration.Room);
const roomToPlaceIn = rooms.find(room => room.Name === placedDecoration.Room);
if (!roomToPlaceIn) {
logger.error("room not found");
throw new Error("room not found");
}
if (placedDecoration.MoveId) {
//moved within the same room
if (placedDecoration.OldRoom === placedDecoration.Room) {
const existingDecorationIndex = roomToPlaceIn?.PlacedDecos?.findIndex(
deco => deco._id.toString() === placedDecoration.MoveId
);
if (existingDecorationIndex === -1) {
logger.error("decoration to be moved not found");
throw new Error("decoration to be moved not found");
}
roomToPlaceIn.PlacedDecos[existingDecorationIndex].Pos = placedDecoration.Pos;
roomToPlaceIn.PlacedDecos[existingDecorationIndex].Rot = placedDecoration.Rot;
if (placedDecoration.Scale) {
roomToPlaceIn.PlacedDecos[existingDecorationIndex].Scale = placedDecoration.Scale;
}
await personalRooms.save();
return {
OldRoom: placedDecoration.OldRoom,
NewRoom: placedDecoration.Room,
IsApartment: placedDecoration.IsApartment,
MaxCapacityIncrease: 0 // TODO: calculate capacity change upon removal
};
}
//moved to a different room
const oldRoom = rooms.find(room => room.Name === placedDecoration.OldRoom);
if (!oldRoom) {
logger.error("old room not found");
throw new Error("old room not found");
}
oldRoom.PlacedDecos.pull({ _id: placedDecoration.MoveId });
const newDecoration = {
Type: placedDecoration.Type,
Pos: placedDecoration.Pos,
Rot: placedDecoration.Rot,
Scale: placedDecoration.Scale || 1,
_id: placedDecoration.MoveId
};
//the new room is still roomToPlaceIn
roomToPlaceIn.PlacedDecos.push(newDecoration);
await personalRooms.save();
return {
OldRoom: placedDecoration.OldRoom,
NewRoom: placedDecoration.Room,
IsApartment: placedDecoration.IsApartment,
MaxCapacityIncrease: 0 // TODO: calculate capacity change upon removal
};
}
//TODO: check whether to remove from shipitems
if (placedDecoration.RemoveId) {
room?.PlacedDecos?.pull({ _id: placedDecoration.RemoveId });
roomToPlaceIn.PlacedDecos.pull({ _id: placedDecoration.RemoveId });
await personalRooms.save();
return {
DecoId: placedDecoration.RemoveId,
@ -54,11 +117,13 @@ export const handleSetShipDecorations = async (
// TODO: handle capacity
//place decoration
const decoId = new Types.ObjectId();
room?.PlacedDecos?.push({
roomToPlaceIn.PlacedDecos?.push({
Type: placedDecoration.Type,
Pos: placedDecoration.Pos,
Rot: placedDecoration.Rot,
Scale: placedDecoration.Scale || 1,
_id: decoId
});

View File

@ -1,25 +0,0 @@
import { IOid } from "@/src/types/commonTypes";
import { IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { Types } from "mongoose";
import { IItemConfig } from "./commonInventoryTypes";
export interface ISuitClient extends Omit<ISuitDatabase, "_id"> {
ItemId: IOid;
}
export interface ISuitDatabase {
ItemType: string;
Configs: IItemConfig[];
UpgradeVer?: number;
XP?: number;
InfestationDate?: Date;
Features?: number;
Polarity?: IPolarity[];
Polarized?: number;
ModSlotPurchases?: number;
CustomizationSlotPurchases?: number;
FocusLens?: string;
UnlockLevel?: number;
_id: Types.ObjectId;
ItemId?: IOid; // only in response
}

View File

@ -1,4 +1,4 @@
import { IOid } from "@/src/types/commonTypes";
import { IMongoDate, IOid } from "@/src/types/commonTypes";
import { Types } from "mongoose";
export interface IPolarity {
@ -38,15 +38,8 @@ export interface ISlotsBin {
Slots: number;
}
// ISigCol? IsIgCoL? ISIGCOL!
export interface Isigcol {
t0: number;
t1: number;
en: number;
}
interface IItemConfigBase {
Skins: string[];
export interface IItemConfig {
Skins?: string[];
pricol?: IColor;
attcol?: IColor;
sigcol?: IColor;
@ -56,12 +49,7 @@ interface IItemConfigBase {
cloth?: IColor;
Upgrades?: string[];
Name?: string;
ugly?: boolean;
}
//TODO: Proper names for the different config types, this should be something like
//IItemConfigPlayable
export interface IItemConfig extends IItemConfigBase {
OperatorAmp?: IOid;
Songs?: ISong[];
AbilityOverride?: IAbilityOverride;
PvpUpgrades?: string[];
@ -74,14 +62,59 @@ export interface ISong {
p?: string;
s: string;
}
//TODO: Consider renaming it to loadout instead of config
export interface IOperatorConfigDatabase extends IItemConfigBase {
export interface IOperatorConfigDatabase extends IItemConfig {
_id: Types.ObjectId;
AbilityOverride?: IAbilityOverride; // not present in adultOperator
OperatorAmp?: IOid; // not present in adultOperator
}
export interface IOperatorConfigClient extends Omit<IOperatorConfigDatabase, "_id"> {
ItemId: IOid;
}
export interface IEquipmentSelection {
ItemId: IOid;
mod?: number;
cus?: number;
ItemType?: string;
hide?: boolean;
}
export interface IEquipmentClient extends Omit<IEquipmentDatabase, "_id"> {
ItemId: IOid;
}
export enum EquipmentFeatures {
DOUBLE_CAPACITY = 1,
UTILITY_SLOT = 2,
ARCANE_SLOT = 32,
INCARNON_GENESIS = 512
}
export interface IEquipmentDatabase {
ItemType: string;
ItemName?: string;
Configs: IItemConfig[];
UpgradeVer?: number;
XP?: number;
Features?: number;
Polarized?: number;
Polarity?: IPolarity[];
FocusLens?: string;
ModSlotPurchases?: number;
CustomizationSlotPurchases?: number;
UpgradeType?: string;
UpgradeFingerprint?: string;
InfestationDate?: IMongoDate;
InfestationDays?: number;
InfestationType?: string;
ModularParts?: string[];
UnlockLevel?: number;
Expiry?: IMongoDate;
SkillTree?: string;
ArchonCrystalUpgrades?: IArchonCrystalUpgrade[];
_id: Types.ObjectId;
}
export interface IArchonCrystalUpgrade {
UpgradeType?: string;
Color?: string;
}

View File

@ -2,15 +2,13 @@
import { Document, Types } from "mongoose";
import { IOid, IMongoDate } from "../commonTypes";
import {
IAbilityOverride,
IColor,
FocusSchool,
IPolarity,
IItemConfig,
IOperatorConfigClient
IOperatorConfigClient,
IEquipmentSelection,
IEquipmentDatabase
} from "@/src/types/inventoryTypes/commonInventoryTypes";
import { ISuitDatabase } from "@/src/types/inventoryTypes/SuitTypes";
import { IOperatorLoadOutSigcol, IWeaponDatabase } from "@/src/types/inventoryTypes/weaponTypes";
//Document extends will be deleted soon. TODO: delete and migrate uses to ...
export interface IInventoryDatabaseDocument extends IInventoryDatabase, Document {}
@ -61,48 +59,14 @@ export interface ITypeCount {
ItemCount: number;
}
export interface IGenericItem2 {
ItemType: string;
ItemName: string;
ItemId: IOid;
XP: number;
UpgradeVer: number;
Features: number;
Polarized: number;
CustomizationSlotPurchases: number;
ModSlotPurchases: number;
FocusLens: string;
Expiry: IMongoDate;
Polarity: IPolarity[];
Configs: IItemConfig[];
ModularParts: string[];
SkillTree: string;
UpgradeType: string;
UpgradeFingerprint: string;
OffensiveUpgrade: string;
DefensiveUpgrade: string;
UpgradesExpiry: IMongoDate;
ArchonCrystalUpgrades: [];
}
export interface IGenericItem {
ItemType: string;
XP?: number;
Configs: IItemConfig[];
UpgradeVer: number;
ItemId: IOid;
Features?: number;
Polarity?: IPolarity[];
Polarized?: number;
ModSlotPurchases?: number;
CustomizationSlotPurchases?: number;
}
export interface IGenericItemDatabase extends Omit<IGenericItem, "ItemId"> {
_id: Types.ObjectId;
}
export type TGenericItemKey = "Suits" | "LongGuns" | "Pistols" | "Melee";
export type TEquipmentKey =
| "Suits"
| "LongGuns"
| "Pistols"
| "Melee"
| "SpecialItems"
| "Sentinels"
| "SentinelWeapons";
export interface IDuviriInfo {
Seed: number;
@ -119,12 +83,12 @@ export interface IPendingRecipeResponse extends Omit<IPendingRecipe, "Completion
CompletionDate: IMongoDate;
}
export interface IInventoryResponse {
Horses: IGenericItem[];
DrifterMelee: IGenericItem[];
DrifterGuns: IGenericItem[];
Horses: IEquipmentDatabase[];
DrifterMelee: IEquipmentDatabase[];
DrifterGuns: IEquipmentDatabase[];
DuviriInfo: IDuviriInfo;
Mailbox: IMailbox;
KahlLoadOuts: IGenericItem[];
KahlLoadOuts: IEquipmentDatabase[];
SubscribedToEmails: number;
Created: IMongoDate;
RewardSeed: number;
@ -156,19 +120,19 @@ export interface IInventoryResponse {
ChallengeProgress: IChallengeProgress[];
RawUpgrades: IRawUpgrade[];
ReceivedStartingGear: boolean;
Suits: ISuitDatabase[];
LongGuns: IWeaponDatabase[];
Pistols: IWeaponDatabase[];
Melee: IWeaponDatabase[];
Suits: IEquipmentDatabase[];
LongGuns: IEquipmentDatabase[];
Pistols: IEquipmentDatabase[];
Melee: IEquipmentDatabase[];
Ships: IShipInventory[];
QuestKeys: IQuestKeyResponse[];
FlavourItems: IFlavourItem[];
Scoops: IGenericItem[];
Scoops: IEquipmentDatabase[];
TrainingRetriesLeft: number;
LoadOutPresets: ILoadOutPresets;
CurrentLoadOutIds: Array<any[] | IOid>;
Missions: IMission[];
RandomUpgradesIdentified: number;
RandomUpgradesIdentified?: number;
LastRegionPlayed: string;
XPInfo: ITypeXPItem[];
Recipes: ITypeCount[];
@ -198,15 +162,15 @@ export interface IInventoryResponse {
Affiliations: IAffiliation[];
QualifyingInvasions: any[];
FactionScores: number[];
SpaceSuits: IGenericItem[];
SpaceMelee: IGenericItem[];
SpaceGuns: ISpaceGun[];
SpaceSuits: IEquipmentDatabase[];
SpaceMelee: IEquipmentDatabase[];
SpaceGuns: IEquipmentDatabase[];
ArchwingEnabled: boolean;
PendingSpectreLoadouts: any[];
SpectreLoadouts: ISpectreLoadout[];
SentinelWeapons: IWeaponDatabase[];
Sentinels: IWeaponDatabase[];
EmailItems: ITypeXPItem[];
SentinelWeapons: IEquipmentDatabase[];
Sentinels: IEquipmentDatabase[];
EmailItems: ITypeCount[];
CompletedSyndicates: string[];
FocusXP: IFocusXP;
Wishlist: string[];
@ -216,7 +180,7 @@ export interface IInventoryResponse {
Drones: IDrone[];
StepSequencers: IStepSequencer[];
ActiveAvatarImageType: string;
KubrowPets: IKubrowPet[];
KubrowPets: IEquipmentDatabase[];
ShipDecorations: IConsumable[];
DailyAffiliationCetus: number;
DailyAffiliationQuills: number;
@ -224,14 +188,14 @@ export interface IInventoryResponse {
CompletedJobs: ICompletedJob[];
FocusAbility: string;
FocusUpgrades: IFocusUpgrade[];
OperatorAmps: IOperatorAmp[];
HasContributedToDojo: boolean;
OperatorAmps: IEquipmentDatabase[];
HasContributedToDojo?: boolean;
HWIDProtectEnabled: boolean;
KubrowPetPrints: IKubrowPetPrint[];
AlignmentReplay: IAlignment;
PersonalGoalProgress: IPersonalGoalProgress[];
DailyAffiliationSolaris: number;
SpecialItems: IGenericItem[];
SpecialItems: IEquipmentDatabase[];
ThemeStyle: string;
ThemeBackground: string;
ThemeSounds: string;
@ -242,17 +206,17 @@ export interface IInventoryResponse {
DailyAffiliationVentkids: number;
DailyAffiliationVox: number;
RecentVendorPurchases: Array<number | string>;
Hoverboards: IHoverboard[];
Hoverboards: IEquipmentDatabase[];
NodeIntrosCompleted: string[];
GuildId?: IOid;
CompletedJobChains: ICompletedJobChain[];
SeasonChallengeHistory: ISeasonChallengeHistory[];
MoaPets: IMoaPet[];
SeasonChallengeHistory: ISeasonChallenge[];
MoaPets: IEquipmentDatabase[];
EquippedInstrument: string;
InvasionChainProgress: IInvasionChainProgress[];
DataKnives: IGenericItem[];
DataKnives: IEquipmentDatabase[];
NemesisHistory: INemesisHistory[];
LastNemesisAllySpawnTime: IMongoDate;
LastNemesisAllySpawnTime?: IMongoDate;
Settings: ISettings;
PersonalTechProjects: IPersonalTechProject[];
CrewShips: ICrewShip[];
@ -262,27 +226,27 @@ export interface IInventoryResponse {
CrewShipWeapons: ICrewShipWeapon[];
CrewShipSalvagedWeapons: ICrewShipWeapon[];
CrewShipWeaponSkins: ICrewShipSalvagedWeaponSkin[];
TradeBannedUntil: IMongoDate;
TradeBannedUntil?: IMongoDate;
PlayedParkourTutorial: boolean;
SubscribedToEmailsPersonalized: number;
DailyAffiliationEntrati: number;
DailyAffiliationNecraloid: number;
MechSuits: ISuitDatabase[];
InfestedFoundry: IInfestedFoundry;
MechSuits: IEquipmentDatabase[];
InfestedFoundry?: IInfestedFoundry;
BlessingCooldown: IMongoDate;
CrewShipHarnesses: ICrewShipHarness[];
CrewShipHarnesses: IEquipmentDatabase[];
CrewShipRawSalvage: IConsumable[];
CrewMembers: ICrewMember[];
AdultOperatorLoadOuts: IOperatorConfigClient[];
LotusCustomization: ILotusCustomization;
UseAdultOperatorLoadout: boolean;
UseAdultOperatorLoadout?: boolean;
DailyAffiliationZariman: number;
NemesisAbandonedRewards: string[];
DailyAffiliationKahl: number;
LastInventorySync: IOid;
NextRefill: IMongoDate;
ActiveLandscapeTraps: any[];
EvolutionProgress: any[];
EvolutionProgress?: IEvolutionProgress[];
RepVotes: any[];
LeagueTickets: any[];
Quests: any[];
@ -297,16 +261,6 @@ export interface IInventoryResponse {
DeathSquadable: boolean;
}
export interface IAdultOperatorLoadOut {
Skins: string[];
attcol: IColor;
eyecol: IColor;
facial: IColor;
pricol: IColor;
Upgrades?: string[];
ItemId: IOid;
}
export interface IAffiliation {
Initiated?: boolean;
Standing: number;
@ -384,14 +338,11 @@ export interface ICrewMember {
WeaponId: IOid;
XP: number;
PowersuitType: string;
Configs: ICrewMemberConfig[];
Configs: IItemConfig[];
SecondInCommand: boolean;
ItemId: IOid;
}
// eslint-disable-next-line @typescript-eslint/no-empty-interface
export interface ICrewMemberConfig {}
export interface ISkillEfficiency {
PILOTING: ICombat;
GUNNERY: ICombat;
@ -404,19 +355,13 @@ export interface ICombat {
Assigned: number;
}
export interface ICrewShipHarness {
ItemType: string;
Configs: ICrewShipHarnessConfig[];
Features: number;
UpgradeVer: number;
XP: number;
Polarity: IPolarity[];
Polarized: number;
ItemId: IOid;
}
export interface ICrewShipHarnessConfig {
Upgrades?: string[];
export enum InventorySlot {
SUITS = "SuitBin",
WEAPONS = "WeaponBin",
SPACESUITS = "SpaceSuitBin",
MECHSUITS = "MechBin",
PVE_LOADOUTS = "PveBonusLoadoutBin",
SENTINELS = "SentinelBin"
}
export interface ISlots {
@ -435,25 +380,21 @@ export interface ICrewShipWeapon {
ItemType: string;
UpgradeType?: string;
UpgradeFingerprint?: string;
Configs?: ICrewShipHarnessConfig[];
Configs?: IItemConfig[];
UpgradeVer?: number;
ItemId: IOid;
}
export interface ICrewShip {
ItemType: string;
Configs: ICrewShipConfig[];
Configs: IItemConfig[];
Weapon: ICrewshipWeapon;
Customization: ICustomization;
ItemName: string;
RailjackImage: IFlavourItem;
CrewMembers: ICrewMembers;
ItemId: IOid;
}
export interface ICrewShipConfig {
Skins?: string[];
pricol?: IColor;
_id: Types.ObjectId;
}
export interface ICrewMembers {
@ -476,16 +417,6 @@ export interface IShipExterior {
ShipAttachments?: IShipAttachments;
}
//TODO: check whether it makes sense to use this specifity of color.
export interface IShipExteriorColors {
t0: number;
t1: number;
t2: number;
t3: number;
m0: number;
en: number;
}
export interface IShipAttachments {
HOOD_ORNAMENT: string; //TODO: Others are probably possible
}
@ -504,22 +435,12 @@ export interface ICrewshipWeapon {
PORT_GUNS: IPortGuns;
}
export interface IPilot {
PRIMARY_A: IL;
SECONDARY_A: IL;
}
// L? Bozo.
export interface IL {
ItemId?: IOid;
mod?: number;
cus?: number;
ItemType?: string;
hide?: boolean;
}
export interface IPortGuns {
PRIMARY_A: IL;
PRIMARY_A: IEquipmentSelection;
}
export interface IPilot extends IPortGuns {
SECONDARY_A: IEquipmentSelection;
}
export interface IDiscoveredMarker {
@ -561,47 +482,15 @@ export interface IFusionTreasure {
Sockets: number;
}
export interface IHoverboard {
ItemType: string;
Configs: IHoverboardConfig[];
ModularParts: string[];
ItemName?: string;
Polarity?: IPolarity[];
UpgradeVer: number;
XP: number;
Features: number;
ItemId: IOid;
}
export interface IHoverboardConfig {
Upgrades?: string[];
Skins?: IPurpleSkin[];
pricol?: IColor;
sigcol?: ISigcol;
attcol?: IColor;
}
export enum IPurpleSkin {
Empty = "",
The5Be4Af71A38E4A9306040E15 = "5be4af71a38e4a9306040e15",
The5C930Ac3A38E4A24Bc3Ad5De = "5c930ac3a38e4a24bc3ad5de",
The5C9C6F9857904A7A3B25656B = "5c9c6f9857904a7a3b25656b",
The5Dd8A8E3A38E4A321A45E6A0 = "5dd8a8e3a38e4a321a45e6a0"
}
export interface ISigcol {
t3: number;
}
export interface IInfestedFoundry {
Name: string;
Resources: ITypeCount[];
Slots: number;
XP: number;
ConsumedSuits: IConsumedSuit[];
InvigorationIndex: number;
InvigorationSuitOfferings: string[];
InvigorationsApplied: number;
Name?: string;
Resources?: ITypeCount[];
Slots?: number;
XP?: number;
ConsumedSuits?: IConsumedSuit[];
InvigorationIndex?: number;
InvigorationSuitOfferings?: string[];
InvigorationsApplied?: number;
}
export interface IConsumedSuit {
@ -645,44 +534,13 @@ export interface ITraits {
Personality: string;
BodyType: string;
Head?: string;
Tail?: Tail;
}
export enum Tail {
Empty = "",
LotusTypesGameCatbrowPetTailsCatbrowTailA = "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailA",
LotusTypesGameCatbrowPetTailsCatbrowTailB = "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailB",
LotusTypesGameCatbrowPetTailsCatbrowTailC = "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailC",
LotusTypesGameCatbrowPetTailsCatbrowTailD = "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailD"
Tail?: string;
}
export enum KubrowPetPrintItemType {
LotusTypesGameKubrowPetImprintedTraitPrint = "/Lotus/Types/Game/KubrowPet/ImprintedTraitPrint"
}
export interface IKubrowPet {
ItemType: string;
Configs: IKubrowPetConfig[];
UpgradeVer: number;
Details: IDetails;
XP?: number;
Polarized?: number;
Polarity?: IPolarity[];
Features?: number;
InfestationDate?: IMongoDate;
InfestationDays?: number;
InfestationType?: string;
ItemId: IOid;
ModularParts?: string[];
}
export interface IKubrowPetConfig {
Skins?: string[];
pricol?: IColor;
attcol?: IColor;
Upgrades?: string[];
}
export interface IDetails {
Name: string;
IsPuppy: boolean;
@ -725,74 +583,32 @@ export interface ILibraryPersonalProgress {
//this needs to be checked against ILoadoutDatabase
export interface ILoadOutPresets {
NORMAL: INormal[];
NORMAL_PVP: IArchwing[];
LUNARO: ILunaro[];
ARCHWING: IArchwing[];
SENTINEL: IArchwing[];
OPERATOR: IArchwing[];
GEAR: IGear[];
KDRIVE: IKdrive[];
DATAKNIFE: IArchwing[];
MECH: IMech[];
OPERATOR_ADULT: IArchwing[];
NORMAL: ILoadoutConfigClient[];
NORMAL_PVP: ILoadoutConfigClient[];
LUNARO: ILoadoutConfigClient[];
ARCHWING: ILoadoutConfigClient[];
SENTINEL: ILoadoutConfigClient[];
OPERATOR: ILoadoutConfigClient[];
GEAR: ILoadoutConfigClient[];
KDRIVE: ILoadoutConfigClient[];
DATAKNIFE: ILoadoutConfigClient[];
MECH: ILoadoutConfigClient[];
OPERATOR_ADULT: ILoadoutConfigClient[];
}
export interface IArchwing {
PresetIcon: string;
Favorite: boolean;
n?: string;
s: IL;
l?: IL;
m?: IL;
ItemId: IOid;
p?: IL;
}
export interface IGear {
n: string;
s: IL;
p: IL;
l: IL;
m: IL;
ItemId: IOid;
}
export interface IKdrive {
PresetIcon: string;
Favorite: boolean;
s: IL;
ItemId: IOid;
}
export interface ILunaro {
n: string;
s: IL;
m: IL;
ItemId: IOid;
}
export interface IMech {
PresetIcon: string;
Favorite: boolean;
s: IL;
h: IL;
a: IL;
ItemId: IOid;
}
export interface INormal {
FocusSchool: FocusSchool;
PresetIcon: string;
Favorite: boolean;
n: string;
s: IL;
p: IL;
l: IL;
m: IL;
h: IL;
a?: IL;
export interface ILoadoutConfigClient {
FocusSchool?: FocusSchool;
PresetIcon?: string;
Favorite?: boolean;
n?: string; // Loadout name
s?: IEquipmentSelection; // Suit
p?: IEquipmentSelection;
l?: IEquipmentSelection; // Primary weapon
m?: IEquipmentSelection; // Melee weapon
h?: IEquipmentSelection; // Gravimag weapon
a?: IEquipmentSelection;
ItemId: IOid;
Remove?: boolean; // when client wants to remove a config, it only includes ItemId & Remove.
}
export enum UpgradeType {
@ -805,16 +621,7 @@ export interface ILoreFragmentScan {
ItemType: string;
}
export interface ILotusCustomization {
Upgrades: any[];
PvpUpgrades: any[];
Skins: string[];
pricol: IColor;
attcol: any[];
sigcol: any[];
eyecol: any[];
facial: any[];
Songs: any[];
export interface ILotusCustomization extends IItemConfig {
Persona: string;
}
@ -825,18 +632,6 @@ export interface IMission {
RewardsCooldownTime?: IMongoDate;
}
export interface IMoaPet {
ItemType: string;
Configs: IKubrowPetConfig[];
UpgradeVer: number;
ModularParts: string[];
XP?: number;
Features?: number;
ItemName: string;
Polarity?: IPolarity[];
ItemId: IOid;
}
export interface INemesisHistory {
fp: number;
manifest: Manifest;
@ -871,30 +666,6 @@ export enum Manifest {
LotusTypesGameNemesisKuvaLichKuvaLichManifestVersionTwo = "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionTwo"
}
export interface IOperatorAmp {
ItemType: string;
Configs: IKubrowPetConfig[];
ModularParts?: string[];
XP?: number;
UpgradeVer?: number;
ItemName?: string;
Features?: number;
ItemId: IOid;
}
export interface IOperatorLoadOut {
Skins: string[];
pricol?: IColor;
attcol?: IColor;
eyecol: IColor;
facial?: IColor;
sigcol?: IOperatorLoadOutSigcol;
OperatorAmp?: IOid;
Upgrades?: string[];
AbilityOverride: IAbilityOverride;
ItemId: IOid;
}
export interface IPendingCoupon {
Expiry: IMongoDate;
Discount: number;
@ -1023,12 +794,7 @@ export interface IRawUpgrade {
LastAdded?: IOid;
}
export interface ISeasonChallengeHistory {
challenge: string;
id: string;
}
export interface ISeasonChallengeCompletions {
export interface ISeasonChallenge {
challenge: string;
id: string;
}
@ -1052,30 +818,6 @@ export interface IShipInventory {
ItemId: IOid;
}
export interface ISpaceGun {
ItemType: string;
Configs: ISpaceGunConfig[];
XP?: number;
UpgradeVer?: number;
ItemId: IOid;
Features?: number;
Polarized?: number;
Polarity?: IPolarity[];
UpgradeType?: UpgradeType;
UpgradeFingerprint?: string;
ItemName?: string;
}
export interface ISpaceGunConfig {
Skins?: string[];
pricol?: IColor;
Upgrades?: string[];
}
export interface IPurpleCol {
en: number;
}
export interface ISpectreLoadout {
LongGuns: string;
Melee: string;
@ -1090,7 +832,7 @@ export interface IStepSequencer {
NotePacks: INotePacks;
FingerPrint: string;
Name: string;
ItemId: IOid;
ItemId?: IOid;
}
export interface INotePacks {
@ -1125,3 +867,9 @@ export interface IWebFlags {
Anniversary2021: boolean;
HitDownloadBtn: IMongoDate;
}
export interface IEvolutionProgress {
Progress: number;
Rank: number;
ItemType: string;
}

View File

@ -1,33 +0,0 @@
import { IOid } from "@/src/types/commonTypes";
import { IItemConfig } from "./commonInventoryTypes";
import { IPolarity } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { Types } from "mongoose";
export interface IWeaponClient extends Omit<IWeaponDatabase, "_id"> {
ItemId: IOid;
}
export interface IWeaponDatabase {
ItemType: string;
Configs: IItemConfig[];
UpgradeVer?: number;
XP?: number;
Features?: number;
Polarized?: number;
Polarity?: IPolarity[];
FocusLens?: string;
ModSlotPurchases?: number;
CustomizationSlotPurchases?: number;
UpgradeType?: string;
UpgradeFingerprint?: string;
ItemName?: string;
ModularParts?: string[];
UnlockLevel?: number;
_id: Types.ObjectId;
}
export interface IOperatorLoadOutSigcol {
t0?: number;
t1?: number;
en?: number;
}

View File

@ -1,7 +1,3 @@
import { ISuitClient } from "@/src/types/inventoryTypes/SuitTypes";
import { IFlavourItem } from "@/src/types/inventoryTypes/inventoryTypes";
import { IWeaponClient } from "@/src/types/inventoryTypes/weaponTypes";
export interface IPurchaseRequest {
PurchaseParams: IPurchaseParams;
buildLabel: string;
@ -18,22 +14,7 @@ export interface IPurchaseParams {
ExpectedPrice: number;
}
export interface IPurchaseResponse {
InventoryChanges: {
SuitBin?: IBinChanges;
WeaponBin?: IBinChanges;
MechBin?: IBinChanges;
MechSuits?: ISuitClient[];
Suits?: ISuitClient[];
LongGuns?: IWeaponClient[];
Pistols?: IWeaponClient[];
Melee?: IWeaponClient[];
PremiumCredits?: number;
PremiumCreditsFree?: number;
RegularCredits?: number;
FlavourItems?: IFlavourItem[];
};
}
export type IInventoryChanges = Record<string, IBinChanges | object[]>;
export type IBinChanges = {
count: number;
@ -42,14 +23,6 @@ export type IBinChanges = {
Extra?: number;
};
export enum SlotNameToInventoryName {
SUIT = "SuitBin",
WEAPON = "WeaponBin",
MECHSUIT = "MechBin",
LOADOUT = "PveBonusLoadoutBin",
SENTINEL = "SentinelBin"
}
export type SlotPurchaseName =
| "SuitSlotItem"
| "TwoSentinelSlotItem"

View File

@ -1,18 +1,16 @@
import { IOid } from "./commonTypes";
import { IPolarity, FocusSchool } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { IPolarity, FocusSchool, IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
import {
IBooster,
IChallengeProgress,
IConsumable,
ICrewShipSalvagedWeaponSkin,
IEvolutionProgress,
IMiscItem,
IMission,
IRawUpgrade,
ISeasonChallengeCompletions,
ISeasonChallengeHistory
ISeasonChallenge
} from "./inventoryTypes/inventoryTypes";
import { IWeaponClient } from "./inventoryTypes/weaponTypes";
import { ISuitClient } from "./inventoryTypes/SuitTypes";
export interface IArtifactsRequest {
Upgrade: ICrewShipSalvagedWeaponSkin;
@ -35,18 +33,18 @@ export interface IAffiliationChange {
export interface IUpdateChallengeProgressRequest {
ChallengeProgress: IChallengeProgress[];
SeasonChallengeHistory: ISeasonChallengeHistory[];
SeasonChallengeCompletions: ISeasonChallengeCompletions[];
SeasonChallengeHistory: ISeasonChallenge[];
SeasonChallengeCompletions: ISeasonChallenge[];
}
export interface IMissionInventoryUpdateRequest {
rewardsMultiplier?: number;
ActiveBoosters?: IBooster[];
AffiliationChanges?: IAffiliationChange[];
LongGuns?: IWeaponClient[];
Pistols?: IWeaponClient[];
Suits?: ISuitClient[];
Melee?: IWeaponClient[];
LongGuns?: IEquipmentClient[];
Pistols?: IEquipmentClient[];
Suits?: IEquipmentClient[];
Melee?: IEquipmentClient[];
RawUpgrades?: IRawUpgrade[];
MiscItems?: IMiscItem[];
Consumables?: IConsumable[];
@ -56,6 +54,7 @@ export interface IMissionInventoryUpdateRequest {
RewardInfo?: IMissionInventoryUpdateRequestRewardInfo;
FusionPoints?: number;
Missions?: IMission;
EvolutionProgress?: IEvolutionProgress[];
}
export interface IMissionInventoryUpdateRequestRewardInfo {

View File

@ -1,6 +1,7 @@
import { IOid } from "@/src/types/commonTypes";
import { IItemConfig, IOperatorConfigClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { Types } from "mongoose";
import { ILoadoutConfigClient } from "./inventoryTypes/inventoryTypes";
export interface ISaveLoadoutRequest {
LoadOuts: ILoadoutClient;
@ -32,6 +33,7 @@ export interface ISaveLoadoutRequest {
CurrentLoadOutIds: IOid[];
ValidNewLoadoutId: string;
EquippedGear: string[];
UseAdultOperatorLoadout: boolean;
}
export interface ISaveLoadoutRequestNoUpgradeVer extends Omit<ISaveLoadoutRequest, "UpgradeVer"> {}
@ -72,23 +74,3 @@ export interface ILoadoutEntry {
export interface ILoadoutConfigDatabase extends Omit<ILoadoutConfigClient, "ItemId"> {
_id: Types.ObjectId;
}
// for request and response from and to client
export interface ILoadoutConfigClient {
ItemId: IOid;
Remove?: boolean; // when client wants to remove a config, it only includes ItemId & Remove.
n?: string;
PresetIcon?: string;
Favorite?: boolean;
s?: IEquipmentSelection;
p?: IEquipmentSelection;
l?: IEquipmentSelection;
m?: IEquipmentSelection;
}
export interface IEquipmentSelection {
ItemId?: IOid;
mod?: number;
cus?: number;
hide?: boolean;
}

View File

@ -69,6 +69,7 @@ export interface IPlacedDecosDatabase {
Type: string;
Pos: [number, number, number];
Rot: [number, number, number];
Scale: number;
_id: Types.ObjectId;
}
@ -100,12 +101,17 @@ export interface IShipDecorationsRequest {
Rot: [number, number, number];
Room: string;
IsApartment: boolean;
RemoveId: string;
RemoveId?: string;
MoveId?: string;
OldRoom?: string;
Scale?: number;
}
export interface IShipDecorationsResponse {
DecoId: string;
Room: string;
DecoId?: string;
Room?: string;
IsApartment: boolean;
MaxCapacityIncrease?: number;
OldRoom?: string;
NewRoom?: string;
}

File diff suppressed because it is too large Load Diff

View File

@ -1249,6 +1249,11 @@
"Tier": 1,
"Tag": "SolNode721"
},
{
"Completes": 1,
"Tier": 1,
"Tag": "SolNode723"
},
{
"Completes": 1,
"Tier": 1,
@ -1516,6 +1521,7 @@
},
{
"Completes": 1,
"Tier": 1,
"Tag": "UranusToNeptuneJunction"
},
{

View File

@ -1,38 +0,0 @@
[
"/Lotus/Types/Keys/VorsPrize/VorsPrizeQuestKeyChain",
"/Lotus/Types/Keys/GlassQuest/GlassQuestKeyChain",
"/Lotus/Types/Keys/SolarisQuest/SolarisQuestKeyChain",
"/Lotus/Types/Keys/InfestedIntroQuest/InfestedIntroQuestKeyChain",
"/Lotus/Types/Keys/KubrowQuest/KubrowQuestKeyChain",
"/Lotus/Types/Keys/ArchwingQuest/ArchwingQuestKeyChain",
"/Lotus/Types/Keys/GetClemQuest/GetClemQuestKeyChain",
"/Lotus/Types/Keys/SpyQuestKeyChain/SpyQuestKeyChain",
"/Lotus/Types/Keys/DragonQuest/DragonQuestKeyChain",
"/Lotus/Types/Keys/LimboQuest/LimboQuestKeyChain",
"/Lotus/Types/Keys/SentientQuest/SentientQuestKeyChain",
"/Lotus/Types/Keys/OrokinMoonQuest/OrokinMoonQuestKeyChain",
"/Lotus/Types/Keys/MirageQuest/MirageQuestKeyChain",
"/Lotus/Types/Keys/WarWithinQuest/WarWithinQuestKeyChain",
"/Lotus/Types/Keys/InfestedAladVQuest/InfestedAladVQuestKeyChain",
"/Lotus/Types/Keys/GolemQuest/GolemQuestKeyChainItem",
"/Lotus/Types/Keys/BardQuest/BardQuestKeyChain",
"/Lotus/Types/Keys/FairyQuest/FairyQuestKeyChain",
"/Lotus/Types/Keys/IndexQuest/IndexQuestKeyChain",
"/Lotus/Types/Keys/PriestFrameQuest/PriestQuestKeyChain",
"/Lotus/Types/Keys/ApostasyQuest/ApostasyKeyChain",
"/Lotus/Types/Keys/SacrificeQuest/SacrificeQuestKeyChain",
"/Lotus/Types/Keys/ChimeraQuest/ChimeraKeyChain",
"/Lotus/Types/Keys/MummyQuest/MummyQuestKeyChain",
"/Lotus/Types/Keys/RailJackBuildQuest/RailjackBuildQuestKeyChain",
"/Lotus/Types/Keys/NewWarIntroQuest/NewWarIntroKeyChain",
"/Lotus/Types/Keys/ProteaQuest/ProteaQuestKeyChain",
"/Lotus/Types/Keys/RevenantQuest/RevenantQuestKeyChain",
"/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain",
"/Lotus/Types/Keys/WraithQuest/WraithQuestKeyChain",
"/Lotus/Types/Keys/YareliQuest/YareliQuestKeyChain",
"/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain",
"/Lotus/Types/Keys/ZarimanQuest/ZarimanQuestKeyChain",
"/Lotus/Types/Keys/KahlQuest/KahlQuestKeyChain",
"/Lotus/Types/Keys/DuviriQuest/DuviriQuestKeyChain",
"/Lotus/Types/Keys/EntratiLab/EntratiQuestKeyChain"
]

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,301 @@
{
"VendorInfo": {
"_id": {
"$oid": "598a090d9a4a313746fd1f24"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Ostron/MaskSalesmanManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Skins/Ostron/RevenantMask",
"ItemPrices": [
{
"ItemCount": 1,
"ItemType": "/Lotus/Types/Gameplay/Eidolon/Resources/CetusWispItem",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "63ed01ef4c37f93d0b797674"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyThumper",
"ItemPrices": [
{
"ItemCount": 2,
"ItemType": "/Lotus/Types/Gameplay/Eidolon/Resources/CetusWispItem",
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/BothUncommonFishBPartItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/Eidolon/Resources/NistlebrushItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Eidolon/CommonOreAAlloyAItem",
"ItemCount": 32,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "63ed01ef4c37f93d0b797675"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyThumperMedium",
"ItemPrices": [
{
"ItemCount": 4,
"ItemType": "/Lotus/Types/Gameplay/Eidolon/Resources/CetusWispItem",
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Eidolon/CommonGemBCutAItem",
"ItemCount": 24,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/BothUncommonFishAPartItem",
"ItemCount": 18,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/BothUncommonFishBPartItem",
"ItemCount": 27,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "63ed01ef4c37f93d0b797676"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyThumperLarge",
"ItemPrices": [
{
"ItemCount": 6,
"ItemType": "/Lotus/Types/Gameplay/Eidolon/Resources/CetusWispItem",
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Eidolon/CommonGemACutAItem",
"ItemCount": 35,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/BothCommonFishAPartItem",
"ItemCount": 95,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/Eidolon/Resources/NistlebrushItem",
"ItemCount": 60,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "63ed01ef4c37f93d0b797677"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/SynthicatorRecipes/FlareBlueBlueprint",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/BothUncommonFishBPartItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/DayCommonFishCPartItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6651291214e90115b91b50a1"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/SynthicatorRecipes/FlareRedBlueprint",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Eidolon/CommonOreAAlloyAItem",
"ItemCount": 37,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/BothUncommonFishAPartItem",
"ItemCount": 7,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6651291214e90115b91b50a2"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Skins/Ostron/VoltMask",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Eidolon/CommonOreBAlloyBItem",
"ItemCount": 34,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/Eidolon/Resources/GrokdrulItem",
"ItemCount": 17,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6651291214e90115b91b50a3"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Skins/Ostron/MagMask",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/DayCommonFishBPartItem",
"ItemCount": 16,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/Eidolon/Resources/ForestRodentPartItem",
"ItemCount": 5,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6651291214e90115b91b50a4"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Skins/Ostron/ExcaliburMask",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Eidolon/Resources/BirdOfPreyPartItem",
"ItemCount": 5,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/Eidolon/Resources/GrokdrulItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6651291214e90115b91b50a5"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Skins/Ostron/GrineerMask",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/DayCommonFishBPartItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Eidolon/CommonOreAAlloyAItem",
"ItemCount": 31,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6651291214e90115b91b50a6"
}
}
],
"PropertyTextHash": "6AACA376DA34B35B5C16F1B40DBC017D",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -2,66 +2,82 @@
"SaleInfos": [
{
"Name": "Ostron",
"Expiry": { "$date": { "$numberLong": "1683586800000" } },
"Revision": 3045,
"Expiry": {
"$date": {
"$numberLong": "9999999900000"
}
},
"Revision": 3453,
"Weapons": [
{
"ItemType": "/Lotus/Weapons/Ostron/Melee/LotusModularWeapon",
"PremiumPrice": 171,
"PremiumPrice": 162,
"ModularParts": [
"/Lotus/Weapons/Ostron/Melee/ModularMelee01/Handle/HandleFive",
"/Lotus/Weapons/Ostron/Melee/ModularMelee01/Tip/TipSix",
"/Lotus/Weapons/Ostron/Melee/ModularMelee01/Balance/BalanceDamageICritII"
"/Lotus/Weapons/Ostron/Melee/ModularMelee01/Tip/TipFour",
"/Lotus/Weapons/Ostron/Melee/ModularMelee01/Balance/BalanceSpeedICritII"
]
}
]
},
{
"Name": "SolarisUnitedHoverboard",
"Expiry": { "$date": { "$numberLong": "1683586800000" } },
"Revision": 1650,
"Expiry": {
"$date": {
"$numberLong": "9999999900000"
}
},
"Revision": 2058,
"Weapons": [
{
"ItemType": "/Lotus/Types/Vehicles/Hoverboard/HoverboardSuit",
"PremiumPrice": 51,
"ModularParts": [
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardCorpusC/HoverboardCorpusCDeck",
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardCorpusC/HoverboardCorpusCEngine",
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardCorpusB/HoverboardCorpusBFront",
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardCorpusC/HoverboardCorpusCJet"
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardSolarisA/HoverboardSolarisADeck",
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardCorpusA/HoverboardCorpusAEngine",
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardSolarisA/HoverboardSolarisAFront",
"/Lotus/Types/Vehicles/Hoverboard/HoverboardParts/PartComponents/HoverboardCorpusB/HoverboardCorpusBJet"
]
}
]
},
{
"Name": "SolarisUnitedMoaPet",
"Expiry": { "$date": { "$numberLong": "1683586800000" } },
"Revision": 1650,
"Expiry": {
"$date": {
"$numberLong": "9999999900000"
}
},
"Revision": 2058,
"Weapons": [
{
"ItemType": "/Lotus/Types/Friendly/Pets/MoaPets/MoaPetPowerSuit",
"PremiumPrice": 175,
"PremiumPrice": 180,
"ModularParts": [
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetLegC",
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetHeadOloro",
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetEngineKrisys",
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetPayloadThermocor"
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetLegB",
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetHeadPara",
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetEngineArcotek",
"/Lotus/Types/Friendly/Pets/MoaPets/MoaPetParts/MoaPetPayloadMunitron"
]
}
]
},
{
"Name": "SolarisUnitedKitGun",
"Expiry": { "$date": { "$numberLong": "1683586800000" } },
"Revision": 1650,
"Expiry": {
"$date": {
"$numberLong": "9999999900000"
}
},
"Revision": 2058,
"Weapons": [
{
"ItemType": "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam",
"PremiumPrice": 157,
"ItemType": "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary",
"PremiumPrice": 184,
"ModularParts": [
"/Lotus/Weapons/SolarisUnited/Primary/SUModularPrimarySet1/Handles/SUModularPrimaryHandleAPart",
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Barrel/SUModularSecondaryBarrelDPart",
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Clip/SUModularCritIReloadIIClipPart"
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Handle/SUModularSecondaryHandleCPart",
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Barrel/SUModularSecondaryBarrelBPart",
"/Lotus/Weapons/SolarisUnited/Secondary/SUModularSecondarySet1/Clip/SUModularStatIReloadIIClipPart"
]
}
]

View File

@ -96,8 +96,8 @@
</div>
<div data-route="/webui/inventory" data-title="Inventory | OpenWF WebUI">
<p id="refresh-note" class="mb-4">
Note: Changes made here will only be reflected in-game when the game re-downloads your inventory.
Visiting the navigation should be the easiest way to trigger that.
Note: Changes made here will only be reflected in-game when the game re-downloads your
inventory. Visiting the navigation should be the easiest way to trigger that.
</p>
<div class="card mb-4">
<h5 class="card-header">Add Items</h5>
@ -144,8 +144,8 @@
</div>
<div data-route="/webui/mods" data-title="Mods | OpenWF WebUI">
<p id="refresh-note" class="mb-4">
Note: Changes made here will only be reflected in-game when the game re-downloads your inventory.
Visiting the navigation should be the easiest way to trigger that.
Note: Changes made here will only be reflected in-game when the game re-downloads your
inventory. Visiting the navigation should be the easiest way to trigger that.
</p>
<div class="row">
<div class="col-xxl-6">
@ -204,60 +204,63 @@
</div>
</div>
<div data-route="/webui/settings" data-title="Settings | OpenWF WebUI">
<div class="card mb-4">
<h5 class="card-header">Change Settings</h5>
<form class="card-body" onsubmit="doChangeSettings();return false;">
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="skipStoryModeChoice" />
<label label class="form-check-label" for="skipStoryModeChoice">Skip Story Mode Choice?</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="skipTutorial" />
<label label class="form-check-label" for="skipTutorial">Skip Tutorial?</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="unlockAllScans" />
<label label class="form-check-label" for="unlockAllScans">Unlock All Scans?</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="unlockAllMissions" />
<label label class="form-check-label" for="unlockAllMissions">Unlock All Missions?</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="unlockAllQuests" />
<label label class="form-check-label" for="unlockAllQuests">Unlock All Quests?</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="completeAllQuests" />
<label label class="form-check-label" for="completeAllQuests">Complete All Quests?</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="infiniteResources" />
<label label class="form-check-label" for="infiniteResources">Infinite Credits and Platinum?</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="unlockallShipFeatures" />
<label label class="form-check-label" for="unlockallShipFeatures">Unlock All Ship Features?</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="unlockAllShipDecorations" />
<label label class="form-check-label" for="unlockAllShipDecorations">Unlock All Ship Decorations?</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="unlockAllFlavourItems" />
<label label class="form-check-label" for="unlockAllFlavourItems">Unlock All Accessories?</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" value="" id="unlockAllSkins" />
<label label class="form-check-label" for="unlockAllSkins">Unlock All Skins?</label>
</div>
<div class="form-check">
<label label class="form-check-label" for="spoofMasteryRank">Spoofed Mastery Rank (-1 to disable)</label>
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" value="" />
</div>
<button class="btn btn-primary" type="submit">Save Settings</button>
</form>
</div>
<form onsubmit="doChangeSettings();return false;">
<div class="form-check">
<input class="form-check-input" type="checkbox" id="skipStoryModeChoice" />
<label class="form-check-label" for="skipStoryModeChoice">Skip Story Mode Choice</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="skipTutorial" />
<label class="form-check-label" for="skipTutorial">Skip Tutorial</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllScans" />
<label class="form-check-label" for="unlockAllScans">Unlock All Scans</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllMissions" />
<label class="form-check-label" for="unlockAllMissions">Unlock All Missions</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllQuests" />
<label class="form-check-label" for="unlockAllQuests">Unlock All Quests</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="completeAllQuests" />
<label class="form-check-label" for="completeAllQuests">Complete All Quests</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="infiniteResources" />
<label class="form-check-label" for="infiniteResources"
>Infinite Credits and Platinum</label
>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllShipFeatures" />
<label class="form-check-label" for="unlockAllShipFeatures">Unlock All Ship Features</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllShipDecorations" />
<label class="form-check-label" for="unlockAllShipDecorations"
>Unlock All Ship Decorations</label
>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllFlavourItems" />
<label class="form-check-label" for="unlockAllFlavourItems">Unlock All Accessories</label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllSkins" />
<label class="form-check-label" for="unlockAllSkins">Unlock All Skins</label>
</div>
<div class="form-group">
<label class="form-label" for="spoofMasteryRank"
>Spoofed Mastery Rank (-1 to disable)</label
>
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" />
</div>
<button class="btn btn-primary mt-3" type="submit">Save Settings</button>
</form>
</div>
</div>
</div>

View File

@ -95,6 +95,12 @@ window.itemListPromise = new Promise(resolve => {
"/Lotus/Weapons/Tenno/Pistol/LotusPistol": { name: "Pistol" },
"/Lotus/Weapons/Tenno/Rifle/LotusRifle": { name: "Rifle" },
"/Lotus/Weapons/Tenno/Shotgun/LotusShotgun": { name: "Shotgun" },
// Modular weapons
"/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam": { name: "Kitgun" },
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary": { name: "Kitgun" },
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam": { name: "Kitgun" },
"/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun": { name: "Kitgun" },
"/Lotus/Weapons/Ostron/Melee/LotusModularWeapon": { name: "Zaw" },
// Missing in data sources
"/Lotus/Upgrades/CosmeticEnhancers/Peculiars/CyoteMod": { name: "Traumatic Peculiar" }
};
@ -103,10 +109,7 @@ window.itemListPromise = new Promise(resolve => {
items.forEach(item => {
if (item.uniqueName in data.badItems) {
item.name += " (Imposter)";
} else if (
item.uniqueName.substr(0, 18) != "/Lotus/Types/Game/" &&
item.uniqueName.substr(0, 18) != "/Lotus/StoreItems/"
) {
} else if (item.uniqueName.substr(0, 18) != "/Lotus/Types/Game/") {
const option = document.createElement("option");
option.setAttribute("data-key", item.uniqueName);
option.value = item.name;
@ -121,7 +124,7 @@ window.itemListPromise = new Promise(resolve => {
});
function updateInventory() {
const req = $.get("/api/inventory.php?" + window.authz);
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
req.done(data => {
window.itemListPromise.then(itemMap => {
document.getElementById("warframe-list").innerHTML = "";
@ -130,6 +133,9 @@ function updateInventory() {
{
const td = document.createElement("td");
td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
if (item.ItemName) {
td.textContent = item.ItemName + " (" + td.textContent + ")";
}
tr.appendChild(td);
}
{
@ -142,12 +148,21 @@ function updateInventory() {
event.preventDefault();
addGearExp("Suits", item.ItemId.$oid, 1_600_000 - item.XP);
};
a.textContent = "Make Rank 30";
a.title = "Make Rank 30";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
td.appendChild(a);
}
{
const a = document.createElement("a");
a.href = "#";
a.onclick = function (event) {
event.preventDefault();
const name = prompt("Enter new custom name:");
renameGear("Suits", item.ItemId.$oid, name);
};
a.title = "Rename";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M0 80V229.5c0 17 6.7 33.3 18.7 45.3l176 176c25 25 65.5 25 90.5 0L418.7 317.3c25-25 25-65.5 0-90.5l-176-176c-12-12-28.3-18.7-45.3-18.7H48C21.5 32 0 53.5 0 80zm112 32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>`;
td.appendChild(a);
const span = document.createElement("span");
span.innerHTML = " &middot; ";
td.appendChild(span);
}
{
const a = document.createElement("a");
@ -156,7 +171,8 @@ function updateInventory() {
event.preventDefault();
disposeOfGear("Suits", item.ItemId.$oid);
};
a.textContent = "Remove";
a.title = "Remove";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
td.appendChild(a);
}
tr.appendChild(td);
@ -171,6 +187,9 @@ function updateInventory() {
{
const td = document.createElement("td");
td.textContent = itemMap[item.ItemType]?.name ?? item.ItemType;
if (item.ItemName) {
td.textContent = item.ItemName + " (" + td.textContent + ")";
}
tr.appendChild(td);
}
{
@ -183,12 +202,21 @@ function updateInventory() {
event.preventDefault();
addGearExp(category, item.ItemId.$oid, 800_000 - item.XP);
};
a.textContent = "Make Rank 30";
a.title = "Make Rank 30";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
td.appendChild(a);
}
{
const a = document.createElement("a");
a.href = "#";
a.onclick = function (event) {
event.preventDefault();
const name = prompt("Enter new custom name:");
renameGear(category, item.ItemId.$oid, name);
};
a.title = "Rename";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M0 80V229.5c0 17 6.7 33.3 18.7 45.3l176 176c25 25 65.5 25 90.5 0L418.7 317.3c25-25 25-65.5 0-90.5l-176-176c-12-12-28.3-18.7-45.3-18.7H48C21.5 32 0 53.5 0 80zm112 32a32 32 0 1 1 0 64 32 32 0 1 1 0-64z"/></svg>`;
td.appendChild(a);
const span = document.createElement("span");
span.innerHTML = " &middot; ";
td.appendChild(span);
}
{
const a = document.createElement("a");
@ -197,7 +225,8 @@ function updateInventory() {
event.preventDefault();
disposeOfGear(category, item.ItemId.$oid);
};
a.textContent = "Remove";
a.title = "Remove";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
td.appendChild(a);
}
tr.appendChild(td);
@ -239,14 +268,10 @@ function updateInventory() {
})
);
a.target = "_blank";
a.textContent = "View Stats";
a.title = "View Stats";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M160 80c0-26.5 21.5-48 48-48h32c26.5 0 48 21.5 48 48V432c0 26.5-21.5 48-48 48H208c-26.5 0-48-21.5-48-48V80zM0 272c0-26.5 21.5-48 48-48H80c26.5 0 48 21.5 48 48V432c0 26.5-21.5 48-48 48H48c-26.5 0-48-21.5-48-48V272zM368 96h32c26.5 0 48 21.5 48 48V432c0 26.5-21.5 48-48 48H368c-26.5 0-48-21.5-48-48V144c0-26.5 21.5-48 48-48z"/></svg>`;
td.appendChild(a);
}
{
const span = document.createElement("span");
span.innerHTML = " &middot; ";
td.appendChild(span);
}
{
const a = document.createElement("a");
a.href = "#";
@ -254,7 +279,8 @@ function updateInventory() {
event.preventDefault();
disposeOfGear("Upgrades", item.ItemId.$oid);
};
a.textContent = "Remove";
a.title = "Remove";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
td.appendChild(a);
}
tr.appendChild(td);
@ -280,12 +306,9 @@ function updateInventory() {
event.preventDefault();
setFingerprint(item.ItemType, item.ItemId, { lvl: maxRank });
};
a.textContent = "Max Rank";
a.title = "Max Rank";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
td.appendChild(a);
const span = document.createElement("span");
span.innerHTML = " &middot; ";
td.appendChild(span);
}
{
const a = document.createElement("a");
@ -294,7 +317,8 @@ function updateInventory() {
event.preventDefault();
disposeOfGear("Upgrades", item.ItemId.$oid);
};
a.textContent = "Remove";
a.title = "Remove";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
td.appendChild(a);
}
tr.appendChild(td);
@ -325,14 +349,10 @@ function updateInventory() {
event.preventDefault();
setFingerprint(item.ItemType, item.LastAdded, { lvl: maxRank });
};
a.textContent = "Max Rank";
a.title = "Max Rank";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
td.appendChild(a);
}
{
const span = document.createElement("span");
span.innerHTML = " &middot; ";
td.appendChild(span);
}
{
const a = document.createElement("a");
a.href = "#";
@ -340,7 +360,8 @@ function updateInventory() {
event.preventDefault();
disposeOfItems("Upgrades", item.ItemType, item.ItemCount);
};
a.textContent = "Remove";
a.title = "Remove";
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
td.appendChild(a);
}
tr.appendChild(td);
@ -430,6 +451,20 @@ function addGearExp(category, oid, xp) {
});
}
function renameGear(category, oid, name) {
revalidateAuthz(() => {
$.post({
url: "/api/nameWeapon.php?" + window.authz + "&Category=" + category + "&ItemId=" + oid + "&webui=1",
contentType: "text/plain",
data: JSON.stringify({
ItemName: name
})
}).done(function () {
updateInventory();
});
});
}
function disposeOfGear(category, oid) {
const data = {
SellCurrency: "SC_RegularCredits",
@ -477,20 +512,21 @@ function disposeOfItems(category, type, count) {
}
function doAcquireMiscItems() {
const uniqueName = getKey(document.getElementById("miscitem-type"));
if (!uniqueName) {
const data = getKey(document.getElementById("miscitem-type"));
if (!data) {
$("#miscitem-type").addClass("is-invalid").focus();
return;
}
const [category, uniqueName] = data.split(":");
revalidateAuthz(() => {
$.post({
url: "/api/missionInventoryUpdate.php?" + window.authz,
contentType: "text/plain",
data: JSON.stringify({
MiscItems: [
[category]: [
{
ItemType: uniqueName,
ItemCount: $("#miscitem-count").val()
ItemCount: parseInt($("#miscitem-count").val())
}
]
})
@ -500,8 +536,8 @@ function doAcquireMiscItems() {
});
}
$("#miscitem-name").on("input", () => {
$("#miscitem-name").removeClass("is-invalid");
$("#miscitem-type").on("input", () => {
$("#miscitem-type").removeClass("is-invalid");
});
function doAcquireRiven() {
@ -537,7 +573,7 @@ function doAcquireRiven() {
})
}).done(function () {
// Get riven's assigned id
$.get("/api/inventory.php?" + window.authz).done(data => {
$.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1").done(data => {
for (const rawUpgrade of data.RawUpgrades) {
if (rawUpgrade.ItemType === uniqueName) {
// Add fingerprint to riven
@ -621,38 +657,40 @@ $("#mod-to-acquire").on("input", () => {
});
function fetchSettings() {
fetch('/custom/config')
.then((response) => response.json())
.then((json) => Object.entries(json).forEach((entry) => {
const [key, value] = entry;
var x = document.getElementById(`${key}`);
if (x!=null) {
if (x.type == "checkbox") {
if (value === true) {
x.setAttribute("checked", "checked")
}
} else if (x.type == "number") {
x.setAttribute("value", `${value}`)
fetch("/custom/config")
.then(response => response.json())
.then(json =>
Object.entries(json).forEach(entry => {
const [key, value] = entry;
var x = document.getElementById(`${key}`);
if (x != null) {
if (x.type == "checkbox") {
if (value === true) {
x.setAttribute("checked", "checked");
}
} else if (x.type == "number") {
x.setAttribute("value", `${value}`);
}
}
}
}));
})
);
}
function doChangeSettings() {
fetch('/custom/config')
.then((response) => response.json())
.then((json) => {
for(var i in json) {
fetch("/custom/config")
.then(response => response.json())
.then(json => {
for (var i in json) {
var x = document.getElementById(`${i}`);
if (x!=null) {
if (x != null) {
if (x.type == "checkbox") {
if (x.checked === true) {
json[i]=true;
json[i] = true;
} else {
json[i]=false;
json[i] = false;
}
} else if (x.type == "number") {
json[i]=parseInt(x.value);
json[i] = parseInt(x.value);
}
}
}
@ -660,6 +698,6 @@ function doChangeSettings() {
url: "/custom/config",
contentType: "text/plain",
data: JSON.stringify(json, null, 2)
})
})
}
});
});
}

View File

@ -20,3 +20,10 @@ body:not(.logged-in) .nav-item.dropdown,
body:not(.logged-in) #refresh-note {
display: none;
}
td.text-end > a > svg {
fill: currentColor;
height: 1em;
margin-left: 0.5em;
margin-bottom: 4px; /* to centre the icon */
}