Compare commits

...

54 Commits

Author SHA1 Message Date
3bcd5827f9 chore(webui): unset nonce when logging out (#2242)
Reviewed-on: OpenWF/SpaceNinjaServer#2242
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-21 14:38:48 -07:00
d16d763977 chore: handle logout POST request for older versions (#2240)
Reviewed-on: OpenWF/SpaceNinjaServer#2240
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-21 14:38:24 -07:00
ff8ec8dbed chore(webui): update bootstrap, add sourcemaps for it (#2238)
Reviewed-on: OpenWF/SpaceNinjaServer#2238
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-21 14:38:04 -07:00
6cdd103c3d chore(dev): improve bulk change handling (#2234)
Fixed abandoned build processes sometimes still triggering a start (causing double-starts) made it more robust in regards to webui changes being intermixed: making the fetch a fire-and-forget to avoid errors, and waiting for the websocket connection to be re-established to avoid the browser attempting to reload when the server may not be up for a few seconds.

Reviewed-on: OpenWF/SpaceNinjaServer#2234
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-21 11:33:59 -07:00
b6f79c1e5c fix: save steel path mission completion (#2233)
Fixes #2228

Reviewed-on: OpenWF/SpaceNinjaServer#2233
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-21 11:25:42 -07:00
2bb3e2afdd chore(webui): update to Spanish translation (#2236)
Reviewed-on: OpenWF/SpaceNinjaServer#2236
Co-authored-by: hxedcl <hxedcl@noreply.localhost>
Co-committed-by: hxedcl <hxedcl@noreply.localhost>
2025-06-21 10:51:57 -07:00
6a60537cd0 chore: remove unused string
Fixup for 2fa6dcc7edb34c9382c31739d8b61a84803d69c2
2025-06-21 17:46:38 +02:00
2fa6dcc7ed feat(webui): handle auth via websocket (#2226)
Now when logging in and out of the game, the webui is notified so it can refresh the nonce, removing the need for constant login requests to revalidate it.

Closes #2223

Reviewed-on: OpenWF/SpaceNinjaServer#2226
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-21 07:26:43 -07:00
93ef9a5348 feat: autogenerate all vendors (#2225)
I went through a few of the still-hardcoded vendors and they seemed to "just work" with autogeneration so I think it's time to say: Closes #1225 and disable the `noVendorPurchaseLimits` cheat by default.

Reviewed-on: OpenWF/SpaceNinjaServer#2225
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-21 07:26:11 -07:00
5d5d0ee560 chore(webui): update Chinese translation (#2227)
Reviewed-on: OpenWF/SpaceNinjaServer#2227
Co-authored-by: CrazyZhang <crazyzhang@noreply.localhost>
Co-committed-by: CrazyZhang <crazyzhang@noreply.localhost>
2025-06-21 07:25:48 -07:00
f84cc54c97 chore: use build & start process for development as well (#2222)
Reviewed-on: OpenWF/SpaceNinjaServer#2222
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-20 18:30:52 -07:00
4cb0f8b167 feat(webui): initial websocket integration to be more responsive (#2221)
For now just handles changes to config.json but in the future might keep the inventory tabs up-to-date with in-game actions.

Reviewed-on: OpenWF/SpaceNinjaServer#2221
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-20 14:00:55 -07:00
eadc9c4ecb feat(webui): max rank plexus (#2219)
Closes #1740

Reviewed-on: OpenWF/SpaceNinjaServer#2219
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-20 14:00:39 -07:00
f41377bb81 chore: npm audit fix (#2220)
Reviewed-on: OpenWF/SpaceNinjaServer#2220
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-20 09:40:53 -07:00
95136e6059 feat: dynamic void fissure missions (#2214)
Closes #1512

Reviewed-on: OpenWF/SpaceNinjaServer#2214
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-20 04:47:45 -07:00
3c64f17e34 feat: missionsCanGiveAllRelics cheat (#2217)
Closes #1060

Reviewed-on: OpenWF/SpaceNinjaServer#2217
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-20 04:42:11 -07:00
3619bdfdb5 feat: autogenerate mask vendor (#2216)
Reviewed-on: OpenWF/SpaceNinjaServer#2216
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-20 04:41:47 -07:00
97064826b2 feat: unlockAllProfitTakerStages cheat (#2215)
Closes #2081

Reviewed-on: OpenWF/SpaceNinjaServer#2215
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-20 04:41:13 -07:00
c6c7a2966b fix: deimos vault bounty detection (#2207)
Related to #388
this should fix incorect rewards for deimos filed bounties

Reviewed-on: OpenWF/SpaceNinjaServer#2207
Reviewed-by: Sainan <sainan@calamity.inc>
Co-authored-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
Co-committed-by: AMelonInsideLemon <166175391+AMelonInsideLemon@users.noreply.github.com>
2025-06-20 04:40:27 -07:00
ce46fa14ac chore: ignore crossPlaySetting in updateChallengeProgress 2025-06-20 05:04:24 +02:00
3186ffe164 feat: autogenerate temple & archimedean vendors (#2208)
So the kuva offer is refreshed every week.

Reviewed-on: OpenWF/SpaceNinjaServer#2208
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-19 19:39:50 -07:00
e686a2d028 chore: report unknown fields in updateChallengeProgress payload (#2210)
Reviewed-on: OpenWF/SpaceNinjaServer#2210
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-19 16:18:49 -07:00
88d4ba6340 feat: dontSubtractVendor{Credit,Platinum,Item,Standing}Cost cheats (#2209)
Closes #1586

Reviewed-on: OpenWF/SpaceNinjaServer#2209
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-19 16:18:35 -07:00
05382beaaf feat: worldState.duviriOverride config (#2206)
Closes #2205

Reviewed-on: OpenWF/SpaceNinjaServer#2206
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-19 16:18:17 -07:00
e136c0494e chore(webui): update to Spanish translation (#2213)
Reviewed-on: OpenWF/SpaceNinjaServer#2213
Co-authored-by: hxedcl <hxedcl@noreply.localhost>
Co-committed-by: hxedcl <hxedcl@noreply.localhost>
2025-06-19 13:38:00 -07:00
ad7b5fc052 fix(webui): incorrect description of topaz shields for blast (#2211)
Reviewed-on: OpenWF/SpaceNinjaServer#2211
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-19 11:15:27 -07:00
61a8d01f64 ci: split docker amd64 & arm64 builds 2025-06-19 14:00:16 +02:00
d78ca91d6c fix(webui): properly handle renaming of pets (#2204)
Reviewed-on: OpenWF/SpaceNinjaServer#2204
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-19 04:23:33 -07:00
4ca4990f89 chore(docker): use file-based config & precompile code in image (#2202)
Reviewed-on: OpenWF/SpaceNinjaServer#2202
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-19 04:23:10 -07:00
bf40155dd4 chore: no-op nemesis mode=w (#2196)
Reviewed-on: OpenWF/SpaceNinjaServer#2196
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-19 04:22:54 -07:00
2e9d3c33b6 chore(webui): update to Spanish translation (#2203)
Reviewed-on: OpenWF/SpaceNinjaServer#2203
Co-authored-by: hxedcl <hxedcl@noreply.localhost>
Co-committed-by: hxedcl <hxedcl@noreply.localhost>
2025-06-18 11:48:22 -07:00
7c8e8fe049 ci: only run on pushes to main
Non-main branches are gonna have to open a PR anyway, so we don't need to run it twice.
2025-06-18 20:42:27 +02:00
0c4065619d chore: support config path being specified via command line argument (#2201)
Reviewed-on: OpenWF/SpaceNinjaServer#2201
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-18 11:34:12 -07:00
dabca46e88 feat(webui): automatically commit toggle changes (#2198)
Closes #2197

Reviewed-on: OpenWF/SpaceNinjaServer#2198
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-18 11:05:07 -07:00
7819d87bbe chore: update nodejs version in Dockerfile (#2199)
Reviewed-on: OpenWF/SpaceNinjaServer#2199
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-18 10:23:39 -07:00
b8b8b6a6c6 feat: railjack valence fusion (#2194)
Closes #1678

Reviewed-on: OpenWF/SpaceNinjaServer#2194
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-18 05:52:16 -07:00
9af0e06b70 feat: add worldState.circuitGameModes config option (#2192)
Closes #749

Reviewed-on: OpenWF/SpaceNinjaServer#2192
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-18 05:51:56 -07:00
f8d0c9e0cb chore: use ChallengesFixVersion that client provides (#2190)
It seems that now we're on version 7, so let's just not hard-code it.

Reviewed-on: OpenWF/SpaceNinjaServer#2190
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-18 05:51:20 -07:00
16e80acb53 chore: add return type to createMessage (#2188)
Reviewed-on: OpenWF/SpaceNinjaServer#2188
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-18 05:50:43 -07:00
6691d4e402 feat: autogenerate steel path honors vendor (#2187)
No more "preprocessing" needed now. Some good progress for #1225, I'd say.

Reviewed-on: OpenWF/SpaceNinjaServer#2187
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-18 05:49:58 -07:00
3dcd2663d3 fix: weaken classic lich when getting all 3 mods correct (#2186)
Fixes #2185

Reviewed-on: OpenWF/SpaceNinjaServer#2186
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-18 05:39:10 -07:00
ffeffe2796 chore(webui): update es (#2195)
Reviewed-on: OpenWF/SpaceNinjaServer#2195
Co-authored-by: hxedcl <hxedcl@noreply.localhost>
Co-committed-by: hxedcl <hxedcl@noreply.localhost>
2025-06-18 05:18:02 -07:00
a9f1368cb7 fix: add UpgradeType field to repaired railjack weapons (#2193)
Reviewed-on: OpenWF/SpaceNinjaServer#2193
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-17 20:58:10 -07:00
cccf6f04a5 feat: xtra cheese rotation (#2191)
This has a bug where the client shows a negative time for "Xtra cheese starts in ..." until it refreshes the world state. This is because we're only providing the new activation as soon as that time/date is reached. However, this is 100% faithful to live.

Reviewed-on: OpenWF/SpaceNinjaServer#2191
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-17 17:32:34 -07:00
1ead581780 chore: improve typing of IFocusXp (#2182)
Any given focus school can be undefined in this object due to importing.

Reviewed-on: OpenWF/SpaceNinjaServer#2182
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-17 05:02:58 -07:00
145d21e30e fix: weaken infested lich (#2181)
Closes #2180

Reviewed-on: OpenWF/SpaceNinjaServer#2181
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-17 05:02:34 -07:00
6c2055a246 feat: echoes of umbra (#2177)
Having this item in the inventory unlocks the helminth option which is helpfully called "remove cyst" to install and uninstall it on a frame.

Reviewed-on: OpenWF/SpaceNinjaServer#2177
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-17 05:02:11 -07:00
01e490768c fix: ensure helminth shard operations don't produce a null shard (#2176)
Reviewed-on: OpenWF/SpaceNinjaServer#2176
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-17 05:01:55 -07:00
2e8fe799d7 feat: setSuitInfection (#2174)
Closes #2172

Reviewed-on: OpenWF/SpaceNinjaServer#2174
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-17 05:01:21 -07:00
53976378bb chore(webui): update Chinese translation (#2184)
Reviewed-on: OpenWF/SpaceNinjaServer#2184
Co-authored-by: qianlishun <qianlishun@noreply.localhost>
Co-committed-by: qianlishun <qianlishun@noreply.localhost>
2025-06-17 03:28:49 -07:00
4e832d3b2c chore(webui): add login/register error messages to translation system (#2179)
Closes #2178

Reviewed-on: OpenWF/SpaceNinjaServer#2179
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-16 15:05:26 -07:00
8c1147998d fix(webui): respond with 200 for successful shard operations (#2175)
Reviewed-on: OpenWF/SpaceNinjaServer#2175
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-16 14:55:56 -07:00
3e99e069be feat: void storm rotation (#2171)
Re #1512

Reviewed-on: OpenWF/SpaceNinjaServer#2171
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-16 14:55:35 -07:00
9731004de6 feat: autogenerate railjack crew member vendor (#2170)
Reviewed-on: OpenWF/SpaceNinjaServer#2170
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-06-16 14:51:47 -07:00
85 changed files with 1870 additions and 6300 deletions

View File

@ -1,6 +1,7 @@
name: Build name: Build
on: on:
push: {} push:
branches: ["main"]
pull_request: {} pull_request: {}
jobs: jobs:
build: build:

View File

@ -4,9 +4,9 @@ on:
branches: branches:
- main - main
jobs: jobs:
docker: docker-amd64:
if: github.repository == 'OpenWF/SpaceNinjaServer' if: github.repository == 'OpenWF/SpaceNinjaServer'
runs-on: ubuntu-latest runs-on: amd64
steps: steps:
- name: Set up Docker buildx - name: Set up Docker buildx
uses: docker/setup-buildx-action@v3 uses: docker/setup-buildx-action@v3
@ -18,8 +18,27 @@ jobs:
- name: Build and push - name: Build and push
uses: docker/build-push-action@v6 uses: docker/build-push-action@v6
with: with:
platforms: linux/amd64,linux/arm64 platforms: linux/amd64
push: true push: true
tags: | tags: |
openwf/spaceninjaserver:latest openwf/spaceninjaserver:latest
openwf/spaceninjaserver:${{ github.sha }} openwf/spaceninjaserver:${{ github.sha }}
docker-arm64:
if: github.repository == 'OpenWF/SpaceNinjaServer'
runs-on: arm64
steps:
- name: Set up Docker buildx
uses: docker/setup-buildx-action@v3
- name: Log in to container registry
uses: docker/login-action@v3
with:
username: openwf
password: ${{ secrets.DOCKERHUB_TOKEN }}
- name: Build and push
uses: docker/build-push-action@v6
with:
platforms: linux/arm64
push: true
tags: |
openwf/spaceninjaserver:latest-arm64
openwf/spaceninjaserver:${{ github.sha }}-arm64

View File

@ -1,53 +1,11 @@
FROM node:18-alpine3.19 FROM node:24-alpine3.21
ENV APP_MONGODB_URL=mongodb://mongodb:27017/openWF RUN apk add --no-cache bash jq
ENV APP_MY_ADDRESS=localhost
ENV APP_HTTP_PORT=80
ENV APP_HTTPS_PORT=443
ENV APP_AUTO_CREATE_ACCOUNT=true
ENV APP_SKIP_TUTORIAL=false
ENV APP_SKIP_ALL_DIALOGUE=false
ENV APP_UNLOCK_ALL_SCANS=false
ENV APP_UNLOCK_ALL_MISSIONS=false
ENV APP_INFINITE_CREDITS=false
ENV APP_INFINITE_PLATINUM=false
ENV APP_INFINITE_ENDO=false
ENV APP_INFINITE_REGAL_AYA=false
ENV APP_INFINITE_HELMINTH_MATERIALS=false
ENV APP_CLAIMING_BLUEPRINT_REFUNDS_INGREDIENTS=false
ENV APP_DONT_SUBTRACT_VOIDTRACES=false
ENV APP_DONT_SUBTRACT_CONSUMABLES=false
ENV APP_UNLOCK_ALL_SHIP_FEATURES=false
ENV APP_UNLOCK_ALL_SHIP_DECORATIONS=false
ENV APP_UNLOCK_ALL_FLAVOUR_ITEMS=false
ENV APP_UNLOCK_ALL_SKINS=false
ENV APP_UNLOCK_ALL_CAPTURA_SCENES=false
ENV APP_UNIVERSAL_POLARITY_EVERYWHERE=false
ENV APP_UNLOCK_DOUBLE_CAPACITY_POTATOES_EVERYWHERE=false
ENV APP_UNLOCK_EXILUS_EVERYWHERE=false
ENV APP_UNLOCK_ARCANES_EVERYWHERE=false
ENV APP_NO_DAILY_FOCUS_LIMIT=false
ENV APP_NO_ARGON_CRYSTAL_DECAY=false
ENV APP_NO_MASTERY_RANK_UP_COOLDOWN=false
ENV APP_NO_VENDOR_PURCHASE_LIMITS=true
ENV APP_NO_DEATH_MARKS=false
ENV APP_NO_KIM_COOLDOWNS=false
ENV APP_SYNDICATE_MISSIONS_REPEATABLE=false
ENV APP_INSTANT_FINISH_RIVEN_CHALLENGE=false
ENV APP_INSTANT_RESOURCE_EXTRACTOR_DRONES=false
ENV APP_NO_RESOURCE_EXTRACTOR_DRONES_DAMAGE=false
ENV APP_SKIP_CLAN_KEY_CRAFTING=false
ENV APP_NO_DOJO_ROOM_BUILD_STAGE=false
ENV APP_NO_DECO_BUILD_STAGE=false
ENV APP_FAST_DOJO_ROOM_DESTRUCTION=false
ENV APP_NO_DOJO_RESEARCH_COSTS=false
ENV APP_NO_DOJO_RESEARCH_TIME=false
ENV APP_FAST_CLAN_ASCENSION=false
ENV APP_SPOOF_MASTERY_RANK=-1
RUN apk add --no-cache bash sed wget jq
COPY . /app COPY . /app
WORKDIR /app WORKDIR /app
RUN npm i --omit=dev
RUN npm run build
ENTRYPOINT ["/app/docker-entrypoint.sh"] ENTRYPOINT ["/app/docker-entrypoint.sh"]

View File

@ -16,6 +16,7 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`. - `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
- `worldState.eidolonOverride` can be set to `day` or `night` to lock the time to day/fass and night/vome on Plains of Eidolon/Cambion Drift. - `worldState.eidolonOverride` can be set to `day` or `night` to lock the time to day/fass and night/vome on Plains of Eidolon/Cambion Drift.
- `worldState.vallisOverride` can be set to `warm` or `cold` to lock the temperature on Orb Vallis. - `worldState.vallisOverride` can be set to `warm` or `cold` to lock the temperature on Orb Vallis.
- `worldState.duviriOverride` can be set to `joy`, `anger`, `envy`, `sorrow`, or `fear` to lock the Duviri spiral.
- `worldState.nightwaveOverride` will lock the nightwave season, assuming the client is new enough for it. Valid values: - `worldState.nightwaveOverride` will lock the nightwave season, assuming the client is new enough for it. Valid values:
- `RadioLegionIntermission13Syndicate` for Nora's Mix Vol. 9 - `RadioLegionIntermission13Syndicate` for Nora's Mix Vol. 9
- `RadioLegionIntermission12Syndicate` for Nora's Mix Vol. 8 - `RadioLegionIntermission12Syndicate` for Nora's Mix Vol. 8
@ -33,3 +34,4 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi
- `RadioLegion2Syndicate` for The Emissary - `RadioLegion2Syndicate` for The Emissary
- `RadioLegionIntermissionSyndicate` for Intermission I - `RadioLegionIntermissionSyndicate` for Intermission I
- `RadioLegionSyndicate` for The Wolf of Saturn Six - `RadioLegionSyndicate` for The Wolf of Saturn Six
- `worldState.circuitGameModes` can be provided with an array of valid game modes (`Survival`, `VoidFlood`, `Excavation`, `Defense`, `Exterminate`, `Assassination`, `Alchemy`)

View File

@ -20,6 +20,10 @@
"infiniteRegalAya": false, "infiniteRegalAya": false,
"infiniteHelminthMaterials": false, "infiniteHelminthMaterials": false,
"claimingBlueprintRefundsIngredients": false, "claimingBlueprintRefundsIngredients": false,
"dontSubtractPurchaseCreditCost": false,
"dontSubtractPurchasePlatinumCost": false,
"dontSubtractPurchaseItemCost": false,
"dontSubtractPurchaseStandingCost": false,
"dontSubtractVoidTraces": false, "dontSubtractVoidTraces": false,
"dontSubtractConsumables": false, "dontSubtractConsumables": false,
"unlockAllShipFeatures": false, "unlockAllShipFeatures": false,
@ -35,10 +39,11 @@
"noDailyFocusLimit": false, "noDailyFocusLimit": false,
"noArgonCrystalDecay": false, "noArgonCrystalDecay": false,
"noMasteryRankUpCooldown": false, "noMasteryRankUpCooldown": false,
"noVendorPurchaseLimits": true, "noVendorPurchaseLimits": false,
"noDeathMarks": false, "noDeathMarks": false,
"noKimCooldowns": false, "noKimCooldowns": false,
"syndicateMissionsRepeatable": false, "syndicateMissionsRepeatable": false,
"unlockAllProfitTakerStages": false,
"instantFinishRivenChallenge": false, "instantFinishRivenChallenge": false,
"instantResourceExtractorDrones": false, "instantResourceExtractorDrones": false,
"noResourceExtractorDronesDamage": false, "noResourceExtractorDronesDamage": false,
@ -49,6 +54,7 @@
"noDojoResearchCosts": false, "noDojoResearchCosts": false,
"noDojoResearchTime": false, "noDojoResearchTime": false,
"fastClanAscension": false, "fastClanAscension": false,
"missionsCanGiveAllRelics": false,
"spoofMasteryRank": -1, "spoofMasteryRank": -1,
"nightwaveStandingMultiplier": 1, "nightwaveStandingMultiplier": 1,
"worldState": { "worldState": {
@ -58,7 +64,9 @@
"starDays": true, "starDays": true,
"eidolonOverride": "", "eidolonOverride": "",
"vallisOverride": "", "vallisOverride": "",
"nightwaveOverride": "" "duviriOverride": "",
"nightwaveOverride": "",
"circuitGameModes": null
}, },
"dev": { "dev": {
"keepVendorsExpired": false "keepVendorsExpired": false

View File

@ -1,62 +1,20 @@
services: services:
spaceninjaserver: spaceninjaserver:
# build: . # The image to use. If you have an ARM CPU, replace 'latest' with 'latest-arm64'.
image: openwf/spaceninjaserver:latest image: openwf/spaceninjaserver:latest
environment:
APP_MONGODB_URL: mongodb://openwfagent:spaceninjaserver@mongodb:27017/
# Following environment variables are set to default image values.
# Uncomment to edit.
# APP_MY_ADDRESS: localhost
# APP_HTTP_PORT: 80
# APP_HTTPS_PORT: 443
# APP_AUTO_CREATE_ACCOUNT: true
# APP_SKIP_TUTORIAL: false
# APP_SKIP_ALL_DIALOGUE: false
# APP_UNLOCK_ALL_SCANS: false
# APP_UNLOCK_ALL_MISSIONS: false
# APP_INFINITE_CREDITS: false
# APP_INFINITE_PLATINUM: false
# APP_INFINITE_ENDO: false
# APP_INFINITE_REGAL_AYA: false
# APP_INFINITE_HELMINTH_MATERIALS: false
# APP_CLAIMING_BLUEPRINT_REFUNDS_INGREDIENTS: false
# APP_DONT_SUBTRACT_VOIDTRACES: false
# APP_DONT_SUBTRACT_CONSUMABLES: false
# APP_UNLOCK_ALL_SHIP_FEATURES: false
# APP_UNLOCK_ALL_SHIP_DECORATIONS: false
# APP_UNLOCK_ALL_FLAVOUR_ITEMS: false
# APP_UNLOCK_ALL_SKINS: false
# APP_UNLOCK_ALL_CAPTURA_SCENES: false
# APP_UNIVERSAL_POLARITY_EVERYWHERE: false
# APP_UNLOCK_DOUBLE_CAPACITY_POTATOES_EVERYWHERE: false
# APP_UNLOCK_EXILUS_EVERYWHERE: false
# APP_UNLOCK_ARCANES_EVERYWHERE: false
# APP_NO_DAILY_FOCUS_LIMIT: false
# APP_NO_ARGON_CRYSTAL_DECAY: false
# APP_NO_MASTERY_RANK_UP_COOLDOWN: false
# APP_NO_VENDOR_PURCHASE_LIMITS: true
# APP_NO_DEATH_MARKS: false
# APP_NO_KIM_COOLDOWNS: false
# APP_SYNDICATE_MISSIONS_REPEATABLE: false
# APP_INSTANT_FINISH_RIVEN_CHALLENGE: false
# APP_INSTANT_RESOURCE_EXTRACTOR_DRONES: false
# APP_NO_RESOURCE_EXTRACTOR_DRONES_DAMAGE: false
# APP_SKIP_CLAN_KEY_CRAFTING: false
# APP_NO_DOJO_ROOM_BUILD_STAGE: false
# APP_NO_DECO_BUILD_STAGE: false
# APP_FAST_DOJO_ROOM_DESTRUCTION: false
# APP_NO_DOJO_RESEARCH_COSTS: false
# APP_NO_DOJO_RESEARCH_TIME: false
# APP_FAST_CLAN_ASCENSION: false
# APP_SPOOF_MASTERY_RANK: -1
volumes: volumes:
- ./docker-data/static:/app/static/data - ./docker-data/conf:/app/conf
- ./docker-data/static-data:/app/static/data
- ./docker-data/logs:/app/logs - ./docker-data/logs:/app/logs
ports: ports:
- 80:80 - 80:80
- 443:443 - 443:443
# Normally, the image is fetched from Docker Hub, but you can use the local Dockerfile by removing "image" above and adding this:
#build: .
# Works best when using `docker-compose up --force-recreate --build`.
depends_on: depends_on:
- mongodb - mongodb
mongodb: mongodb:
@ -66,3 +24,4 @@ services:
MONGO_INITDB_ROOT_PASSWORD: spaceninjaserver MONGO_INITDB_ROOT_PASSWORD: spaceninjaserver
volumes: volumes:
- ./docker-data/database:/data/db - ./docker-data/database:/data/db
command: mongod --quiet --logpath /dev/null

View File

@ -1,24 +1,8 @@
#!/bin/bash #!/bin/bash
set -e set -e
# Set up the configuration file using environment variables. if [ ! -f conf/config.json ]; then
echo '{ jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config.json.example > /app/conf/config.json
"logger": { fi
"files": true,
"level": "trace",
"__valid_levels": "fatal, error, warn, info, http, debug, trace"
}
}
' > config.json
for config in $(env | grep "APP_") exec npm run start -- --configPath conf/config.json
do
var=$(echo "${config}" | tr '[:upper:]' '[:lower:]' | sed 's/app_//g' | sed -E 's/_([a-z])/\U\1/g' | sed 's/=.*//g')
val=$(echo "${config}" | sed 's/.*=//g')
jq --arg variable "$var" --arg value "$val" '.[$variable] += try [$value|fromjson][] catch $value' config.json > config.tmp
mv config.tmp config.json
done
npm i --omit=dev
npm run build
exec npm run start

602
package-lock.json generated
View File

@ -11,6 +11,7 @@
"dependencies": { "dependencies": {
"@types/express": "^5", "@types/express": "^5",
"@types/morgan": "^1.9.9", "@types/morgan": "^1.9.9",
"@types/ws": "^8.18.1",
"crc-32": "^1.2.2", "crc-32": "^1.2.2",
"express": "^5", "express": "^5",
"json-with-bigint": "^3.4.4", "json-with-bigint": "^3.4.4",
@ -18,20 +19,21 @@
"morgan": "^1.10.0", "morgan": "^1.10.0",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"typescript": "^5.5", "typescript": "^5.5",
"warframe-public-export-plus": "^0.5.67", "warframe-public-export-plus": "^0.5.68",
"warframe-riven-info": "^0.1.2", "warframe-riven-info": "^0.1.2",
"winston": "^3.17.0", "winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0" "winston-daily-rotate-file": "^5.0.0",
"ws": "^8.18.2"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.28.0", "@typescript-eslint/eslint-plugin": "^8.28.0",
"@typescript-eslint/parser": "^8.28.0", "@typescript-eslint/parser": "^8.28.0",
"@typescript/native-preview": "^7.0.0-dev.20250523.1", "@typescript/native-preview": "^7.0.0-dev.20250523.1",
"chokidar": "^4.0.3",
"eslint": "^8", "eslint": "^8",
"eslint-plugin-prettier": "^5.2.5", "eslint-plugin-prettier": "^5.2.5",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"ts-node-dev": "^2.0.0", "tree-kill": "^1.2.2"
"tsconfig-paths": "^4.2.0"
} }
}, },
"node_modules/@colors/colors": { "node_modules/@colors/colors": {
@ -43,19 +45,6 @@
"node": ">=0.1.90" "node": ">=0.1.90"
} }
}, },
"node_modules/@cspotcode/source-map-support": {
"version": "0.8.1",
"resolved": "https://registry.npmjs.org/@cspotcode/source-map-support/-/source-map-support-0.8.1.tgz",
"integrity": "sha512-IchNf6dN4tHoMFIn/7OE8LWZ19Y6q/67Bmf6vnGREv8RSbBVb9LPJxEcnwrcwX6ixSvaiGoomAUvu4YSxXrVgw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/trace-mapping": "0.3.9"
},
"engines": {
"node": ">=12"
}
},
"node_modules/@dabh/diagnostics": { "node_modules/@dabh/diagnostics": {
"version": "2.0.3", "version": "2.0.3",
"resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz", "resolved": "https://registry.npmjs.org/@dabh/diagnostics/-/diagnostics-2.0.3.tgz",
@ -121,9 +110,9 @@
} }
}, },
"node_modules/@eslint/eslintrc/node_modules/brace-expansion": { "node_modules/@eslint/eslintrc/node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -171,9 +160,9 @@
} }
}, },
"node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": { "node_modules/@humanwhocodes/config-array/node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -216,34 +205,6 @@
"dev": true, "dev": true,
"license": "BSD-3-Clause" "license": "BSD-3-Clause"
}, },
"node_modules/@jridgewell/resolve-uri": {
"version": "3.1.2",
"resolved": "https://registry.npmjs.org/@jridgewell/resolve-uri/-/resolve-uri-3.1.2.tgz",
"integrity": "sha512-bRISgCIjP20/tbWSPWMEi54QVPRZExkuD9lJL+UIxUKtwVJA8wW1Trb1jMs1RFXo1CBTNZ/5hpC9QvmKWdopKw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=6.0.0"
}
},
"node_modules/@jridgewell/sourcemap-codec": {
"version": "1.5.0",
"resolved": "https://registry.npmjs.org/@jridgewell/sourcemap-codec/-/sourcemap-codec-1.5.0.tgz",
"integrity": "sha512-gv3ZRaISU3fjPAgNsriBRqGWQL6quFx04YMPW/zD8XMLsU32mhCCbfbO6KZFLjvYpCZ8zyDEgqsgf+PwPaM7GQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@jridgewell/trace-mapping": {
"version": "0.3.9",
"resolved": "https://registry.npmjs.org/@jridgewell/trace-mapping/-/trace-mapping-0.3.9.tgz",
"integrity": "sha512-3Belt6tdc8bPgAtbcmdtNJlirVoTmEb5e2gC94PnkwEW9jI6CAHUeoG85tjWP5WquqfavoMtMwiG4P926ZKKuQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@jridgewell/resolve-uri": "^3.0.3",
"@jridgewell/sourcemap-codec": "^1.4.10"
}
},
"node_modules/@mongodb-js/saslprep": { "node_modules/@mongodb-js/saslprep": {
"version": "1.2.2", "version": "1.2.2",
"resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.2.2.tgz", "resolved": "https://registry.npmjs.org/@mongodb-js/saslprep/-/saslprep-1.2.2.tgz",
@ -304,34 +265,6 @@
"url": "https://opencollective.com/pkgr" "url": "https://opencollective.com/pkgr"
} }
}, },
"node_modules/@tsconfig/node10": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node10/-/node10-1.0.11.tgz",
"integrity": "sha512-DcRjDCujK/kCk/cUe8Xz8ZSpm8mS3mNNpta+jGCA6USEDfktlNvm1+IuZ9eTcDbNk41BHwpHHeW+N1lKCz4zOw==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node12": {
"version": "1.0.11",
"resolved": "https://registry.npmjs.org/@tsconfig/node12/-/node12-1.0.11.tgz",
"integrity": "sha512-cqefuRsh12pWyGsIoBKJA9luFu3mRxCA+ORZvA4ktLSzIuCUtWVxGIuXigEwO5/ywWFMZ2QEGKWvkZG1zDMTag==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node14": {
"version": "1.0.3",
"resolved": "https://registry.npmjs.org/@tsconfig/node14/-/node14-1.0.3.tgz",
"integrity": "sha512-ysT8mhdixWK6Hw3i1V2AeRqZ5WfXg1G43mqoYlM2nc6388Fq5jcXyr5mRsqViLx/GJYdoL0bfXD8nmF+Zn/Iow==",
"dev": true,
"license": "MIT"
},
"node_modules/@tsconfig/node16": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/@tsconfig/node16/-/node16-1.0.4.tgz",
"integrity": "sha512-vxhUy4J8lyeyinH7Azl1pdd43GJhZH/tP2weN8TntQblOY+A0XbT8DJk1/oCPuOOyg/Ja757rG0CgHcWC8OfMA==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/body-parser": { "node_modules/@types/body-parser": {
"version": "1.19.5", "version": "1.19.5",
"resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz", "resolved": "https://registry.npmjs.org/@types/body-parser/-/body-parser-1.19.5.tgz",
@ -437,20 +370,6 @@
"@types/send": "*" "@types/send": "*"
} }
}, },
"node_modules/@types/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/@types/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-xevGOReSYGM7g/kUBZzPqCrR/KYAo+F0yiPc85WFTJa0MSLtyFTVTU6cJu/aV4mid7IffDIWqo69THF2o4JiEQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/strip-json-comments": {
"version": "0.0.30",
"resolved": "https://registry.npmjs.org/@types/strip-json-comments/-/strip-json-comments-0.0.30.tgz",
"integrity": "sha512-7NQmHra/JILCd1QqpSzl8+mJRc8ZHz3uDm8YV1Ks9IhK0epEiTw8aIErbvH9PI+6XbqhyIQy3462nEsn7UVzjQ==",
"dev": true,
"license": "MIT"
},
"node_modules/@types/triple-beam": { "node_modules/@types/triple-beam": {
"version": "1.3.5", "version": "1.3.5",
"resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz", "resolved": "https://registry.npmjs.org/@types/triple-beam/-/triple-beam-1.3.5.tgz",
@ -472,6 +391,15 @@
"@types/webidl-conversions": "*" "@types/webidl-conversions": "*"
} }
}, },
"node_modules/@types/ws": {
"version": "8.18.1",
"resolved": "https://registry.npmjs.org/@types/ws/-/ws-8.18.1.tgz",
"integrity": "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg==",
"license": "MIT",
"dependencies": {
"@types/node": "*"
}
},
"node_modules/@typescript-eslint/eslint-plugin": { "node_modules/@typescript-eslint/eslint-plugin": {
"version": "8.32.0", "version": "8.32.0",
"resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz", "resolved": "https://registry.npmjs.org/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.32.0.tgz",
@ -849,19 +777,6 @@
"acorn": "^6.0.0 || ^7.0.0 || ^8.0.0" "acorn": "^6.0.0 || ^7.0.0 || ^8.0.0"
} }
}, },
"node_modules/acorn-walk": {
"version": "8.3.4",
"resolved": "https://registry.npmjs.org/acorn-walk/-/acorn-walk-8.3.4.tgz",
"integrity": "sha512-ueEepnujpqee2o5aIYnvHU6C0A42MNdsIDeqy5BydrkuC5R1ZuUFnm27EeFJGoEHJQgn3uleRvmTXaJgfXbt4g==",
"dev": true,
"license": "MIT",
"dependencies": {
"acorn": "^8.11.0"
},
"engines": {
"node": ">=0.4.0"
}
},
"node_modules/ajv": { "node_modules/ajv": {
"version": "6.12.6", "version": "6.12.6",
"resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz", "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.12.6.tgz",
@ -905,27 +820,6 @@
"url": "https://github.com/chalk/ansi-styles?sponsor=1" "url": "https://github.com/chalk/ansi-styles?sponsor=1"
} }
}, },
"node_modules/anymatch": {
"version": "3.1.3",
"resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
"integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
"dev": true,
"license": "ISC",
"dependencies": {
"normalize-path": "^3.0.0",
"picomatch": "^2.0.4"
},
"engines": {
"node": ">= 8"
}
},
"node_modules/arg": {
"version": "4.1.3",
"resolved": "https://registry.npmjs.org/arg/-/arg-4.1.3.tgz",
"integrity": "sha512-58S9QDqG0Xx27YwPSt9fJxivjYl432YCwfDMfZ+71RAqUrZef7LrKQZ3LHLOwCS4FLNBplP533Zx895SeOCHvA==",
"dev": true,
"license": "MIT"
},
"node_modules/argparse": { "node_modules/argparse": {
"version": "2.0.1", "version": "2.0.1",
"resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz", "resolved": "https://registry.npmjs.org/argparse/-/argparse-2.0.1.tgz",
@ -964,19 +858,6 @@
"integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/binary-extensions": {
"version": "2.3.0",
"resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
"integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=8"
},
"funding": {
"url": "https://github.com/sponsors/sindresorhus"
}
},
"node_modules/body-parser": { "node_modules/body-parser": {
"version": "2.2.0", "version": "2.2.0",
"resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz", "resolved": "https://registry.npmjs.org/body-parser/-/body-parser-2.2.0.tgz",
@ -998,9 +879,9 @@
} }
}, },
"node_modules/brace-expansion": { "node_modules/brace-expansion": {
"version": "2.0.1", "version": "2.0.2",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.2.tgz",
"integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==", "integrity": "sha512-Jt0vHyM+jmUBqojB7E1NIYadt0vI0Qxjxd2TErW94wDz+E2LAm5vKMXXwg6ZZBTHPuUlDgQHKXvjGBdfcF1ZDQ==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1029,13 +910,6 @@
"node": ">=16.20.1" "node": ">=16.20.1"
} }
}, },
"node_modules/buffer-from": {
"version": "1.1.2",
"resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.2.tgz",
"integrity": "sha512-E+XQCRwSbaaiChtv6k6Dwgc+bx+Bs6vuKJHHl5kox/BaKbhiXzqQOwK4cO22yElGp2OCmjwVhT3HmxgyPGnJfQ==",
"dev": true,
"license": "MIT"
},
"node_modules/bytes": { "node_modules/bytes": {
"version": "3.1.2", "version": "3.1.2",
"resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz", "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
@ -1102,41 +976,19 @@
} }
}, },
"node_modules/chokidar": { "node_modules/chokidar": {
"version": "3.6.0", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"anymatch": "~3.1.2", "readdirp": "^4.0.1"
"braces": "~3.0.2",
"glob-parent": "~5.1.2",
"is-binary-path": "~2.1.0",
"is-glob": "~4.0.1",
"normalize-path": "~3.0.0",
"readdirp": "~3.6.0"
}, },
"engines": { "engines": {
"node": ">= 8.10.0" "node": ">= 14.16.0"
}, },
"funding": { "funding": {
"url": "https://paulmillr.com/funding/" "url": "https://paulmillr.com/funding/"
},
"optionalDependencies": {
"fsevents": "~2.3.2"
}
},
"node_modules/chokidar/node_modules/glob-parent": {
"version": "5.1.2",
"resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
"integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
"dev": true,
"license": "ISC",
"dependencies": {
"is-glob": "^4.0.1"
},
"engines": {
"node": ">= 6"
} }
}, },
"node_modules/color": { "node_modules/color": {
@ -1261,13 +1113,6 @@
"node": ">=0.8" "node": ">=0.8"
} }
}, },
"node_modules/create-require": {
"version": "1.1.1",
"resolved": "https://registry.npmjs.org/create-require/-/create-require-1.1.1.tgz",
"integrity": "sha512-dcKFX3jn0MpIaXjisoRvexIJVEKzaq7z2rZKxf+MSr9TkdmHmsU4m2lcLojrj/FHl8mk5VxMmYA+ftRkP/3oKQ==",
"dev": true,
"license": "MIT"
},
"node_modules/cross-spawn": { "node_modules/cross-spawn": {
"version": "7.0.6", "version": "7.0.6",
"resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz", "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-7.0.6.tgz",
@ -1316,16 +1161,6 @@
"node": ">= 0.8" "node": ">= 0.8"
} }
}, },
"node_modules/diff": {
"version": "4.0.2",
"resolved": "https://registry.npmjs.org/diff/-/diff-4.0.2.tgz",
"integrity": "sha512-58lmxKSA4BNyLz+HHMUzlOEpg09FV+ev6ZMe3vJihgdxzgcwZ8VoEEPmALCZG9LmqfVoNMMKpttIYTVG6uDY7A==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.3.1"
}
},
"node_modules/doctrine": { "node_modules/doctrine": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz", "resolved": "https://registry.npmjs.org/doctrine/-/doctrine-3.0.0.tgz",
@ -1353,16 +1188,6 @@
"node": ">= 0.4" "node": ">= 0.4"
} }
}, },
"node_modules/dynamic-dedupe": {
"version": "0.3.0",
"resolved": "https://registry.npmjs.org/dynamic-dedupe/-/dynamic-dedupe-0.3.0.tgz",
"integrity": "sha512-ssuANeD+z97meYOqd50e04Ze5qp4bPqo8cCkI4TRjZkzAUgIDTrXV1R8QCdINpiI+hw14+rYazvTRdQrz0/rFQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"xtend": "^4.0.0"
}
},
"node_modules/ee-first": { "node_modules/ee-first": {
"version": "1.1.1", "version": "1.1.1",
"resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz", "resolved": "https://registry.npmjs.org/ee-first/-/ee-first-1.1.1.tgz",
@ -1552,9 +1377,9 @@
} }
}, },
"node_modules/eslint/node_modules/brace-expansion": { "node_modules/eslint/node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -1886,21 +1711,6 @@
"dev": true, "dev": true,
"license": "ISC" "license": "ISC"
}, },
"node_modules/fsevents": {
"version": "2.3.3",
"resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
"integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
"dev": true,
"hasInstallScript": true,
"license": "MIT",
"optional": true,
"os": [
"darwin"
],
"engines": {
"node": "^8.16.0 || ^10.6.0 || >=11.0.0"
}
},
"node_modules/function-bind": { "node_modules/function-bind": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz", "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
@ -1983,9 +1793,9 @@
} }
}, },
"node_modules/glob/node_modules/brace-expansion": { "node_modules/glob/node_modules/brace-expansion": {
"version": "1.1.11", "version": "1.1.12",
"resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.12.tgz",
"integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", "integrity": "sha512-9T9UjW3r0UW5c1Q7GTwllptXwhvYmEzFhzMfZ9H7FQWt+uZePjZPjBP/W1ZEyZ1twGWom5/56TF4lPcqjnDHcg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
@ -2173,35 +1983,6 @@
"integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==", "integrity": "sha512-eVRqCvVlZbuw3GrM63ovNSNAeA1K16kaR/LRY/92w0zxQ5/1YzwblUX652i4Xs9RwAGjW9d9y6X88t8OaAJfWQ==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/is-binary-path": {
"version": "2.1.0",
"resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
"integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
"dev": true,
"license": "MIT",
"dependencies": {
"binary-extensions": "^2.0.0"
},
"engines": {
"node": ">=8"
}
},
"node_modules/is-core-module": {
"version": "2.16.1",
"resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.16.1.tgz",
"integrity": "sha512-UfoeMA6fIJ8wTYFEUjelnaGI67v6+N7qXJEvQuIGa99l4xsCruSYOVSQ0uPANn4dAzm8lkYPaKLrrijLq7x23w==",
"dev": true,
"license": "MIT",
"dependencies": {
"hasown": "^2.0.2"
},
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/is-extglob": { "node_modules/is-extglob": {
"version": "2.1.1", "version": "2.1.1",
"resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
@ -2310,19 +2091,6 @@
"integrity": "sha512-AhpYAAaZsPjU7smaBomDt1SOQshi9rEm6BlTbfVwsG1vNmeHKtEedJi62sHZzJTyKNtwzmNnrsd55kjwJ7054A==", "integrity": "sha512-AhpYAAaZsPjU7smaBomDt1SOQshi9rEm6BlTbfVwsG1vNmeHKtEedJi62sHZzJTyKNtwzmNnrsd55kjwJ7054A==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/json5": {
"version": "2.2.3",
"resolved": "https://registry.npmjs.org/json5/-/json5-2.2.3.tgz",
"integrity": "sha512-XmOWe7eyHYH14cLdVPoyg+GOH3rYX++KpzrylJwSW98t3Nk+U8XOl8FWKOgwtzdb8lXGf6zYwDUzeHMWfxasyg==",
"dev": true,
"license": "MIT",
"bin": {
"json5": "lib/cli.js"
},
"engines": {
"node": ">=6"
}
},
"node_modules/kareem": { "node_modules/kareem": {
"version": "2.6.3", "version": "2.6.3",
"resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz", "resolved": "https://registry.npmjs.org/kareem/-/kareem-2.6.3.tgz",
@ -2402,13 +2170,6 @@
"node": ">= 12.0.0" "node": ">= 12.0.0"
} }
}, },
"node_modules/make-error": {
"version": "1.3.6",
"resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
"integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
"dev": true,
"license": "ISC"
},
"node_modules/math-intrinsics": { "node_modules/math-intrinsics": {
"version": "1.1.0", "version": "1.1.0",
"resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz", "resolved": "https://registry.npmjs.org/math-intrinsics/-/math-intrinsics-1.1.0.tgz",
@ -2506,29 +2267,6 @@
"url": "https://github.com/sponsors/isaacs" "url": "https://github.com/sponsors/isaacs"
} }
}, },
"node_modules/minimist": {
"version": "1.2.8",
"resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
"integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
"dev": true,
"license": "MIT",
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/mkdirp": {
"version": "1.0.4",
"resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-1.0.4.tgz",
"integrity": "sha512-vVqVZQyf3WLx2Shd0qJ9xuvqgAyKPLAiqITEtqW0oIUjzo3PePDd6fW9iFz30ef7Ysp/oiWqbhszeGWW2T6Gzw==",
"dev": true,
"license": "MIT",
"bin": {
"mkdirp": "bin/cmd.js"
},
"engines": {
"node": ">=10"
}
},
"node_modules/moment": { "node_modules/moment": {
"version": "2.30.1", "version": "2.30.1",
"resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz", "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
@ -2711,16 +2449,6 @@
"node": ">= 0.6" "node": ">= 0.6"
} }
}, },
"node_modules/normalize-path": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
"integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/object-hash": { "node_modules/object-hash": {
"version": "3.0.0", "version": "3.0.0",
"resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz", "resolved": "https://registry.npmjs.org/object-hash/-/object-hash-3.0.0.tgz",
@ -2883,13 +2611,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/path-parse": {
"version": "1.0.7",
"resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
"integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
"dev": true,
"license": "MIT"
},
"node_modules/path-to-regexp": { "node_modules/path-to-regexp": {
"version": "8.2.0", "version": "8.2.0",
"resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz", "resolved": "https://registry.npmjs.org/path-to-regexp/-/path-to-regexp-8.2.0.tgz",
@ -3048,37 +2769,17 @@
} }
}, },
"node_modules/readdirp": { "node_modules/readdirp": {
"version": "3.6.0", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"dev": true, "dev": true,
"license": "MIT", "license": "MIT",
"dependencies": {
"picomatch": "^2.2.1"
},
"engines": { "engines": {
"node": ">=8.10.0" "node": ">= 14.18.0"
}
},
"node_modules/resolve": {
"version": "1.22.10",
"resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.10.tgz",
"integrity": "sha512-NPRy+/ncIMeDlTAsuqwKIiferiawhefFJtkNSW0qZJEqMEb+qBt/77B/jGeeek+F0uOeN05CDa6HXbbIgtVX4w==",
"dev": true,
"license": "MIT",
"dependencies": {
"is-core-module": "^2.16.0",
"path-parse": "^1.0.7",
"supports-preserve-symlinks-flag": "^1.0.0"
},
"bin": {
"resolve": "bin/resolve"
},
"engines": {
"node": ">= 0.4"
}, },
"funding": { "funding": {
"url": "https://github.com/sponsors/ljharb" "type": "individual",
"url": "https://paulmillr.com/funding/"
} }
}, },
"node_modules/resolve-from": { "node_modules/resolve-from": {
@ -3360,27 +3061,6 @@
"is-arrayish": "^0.3.1" "is-arrayish": "^0.3.1"
} }
}, },
"node_modules/source-map": {
"version": "0.6.1",
"resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
"integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
"dev": true,
"license": "BSD-3-Clause",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/source-map-support": {
"version": "0.5.21",
"resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.21.tgz",
"integrity": "sha512-uBHU3L3czsIyYXKX88fdrGovxdSCoTGDRZ6SYXtSRxLZUzHg5P/66Ht6uoUlHu9EZod+inXhKo3qQgwXUT/y1w==",
"dev": true,
"license": "MIT",
"dependencies": {
"buffer-from": "^1.0.0",
"source-map": "^0.6.0"
}
},
"node_modules/sparse-bitfield": { "node_modules/sparse-bitfield": {
"version": "3.0.3", "version": "3.0.3",
"resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz", "resolved": "https://registry.npmjs.org/sparse-bitfield/-/sparse-bitfield-3.0.3.tgz",
@ -3430,16 +3110,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/strip-bom": {
"version": "3.0.0",
"resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-3.0.0.tgz",
"integrity": "sha512-vavAMRXOgBVNF6nyEEmL3DBK19iRpDcoIwW+swQ+CbGiu7lju6t+JklA1MHweoWtadgt4ISVUsXLyDq34ddcwA==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=4"
}
},
"node_modules/strip-json-comments": { "node_modules/strip-json-comments": {
"version": "3.1.1", "version": "3.1.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz", "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-3.1.1.tgz",
@ -3466,19 +3136,6 @@
"node": ">=8" "node": ">=8"
} }
}, },
"node_modules/supports-preserve-symlinks-flag": {
"version": "1.0.0",
"resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
"integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">= 0.4"
},
"funding": {
"url": "https://github.com/sponsors/ljharb"
}
},
"node_modules/synckit": { "node_modules/synckit": {
"version": "0.11.4", "version": "0.11.4",
"resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.4.tgz", "resolved": "https://registry.npmjs.org/synckit/-/synckit-0.11.4.tgz",
@ -3575,137 +3232,6 @@
"typescript": ">=4.8.4" "typescript": ">=4.8.4"
} }
}, },
"node_modules/ts-node": {
"version": "10.9.2",
"resolved": "https://registry.npmjs.org/ts-node/-/ts-node-10.9.2.tgz",
"integrity": "sha512-f0FFpIdcHgn8zcPSbf1dRevwt047YMnaiJM3u2w2RewrB+fob/zePZcrOyQoLMMO7aBIddLcQIEK5dYjkLnGrQ==",
"dev": true,
"license": "MIT",
"dependencies": {
"@cspotcode/source-map-support": "^0.8.0",
"@tsconfig/node10": "^1.0.7",
"@tsconfig/node12": "^1.0.7",
"@tsconfig/node14": "^1.0.0",
"@tsconfig/node16": "^1.0.2",
"acorn": "^8.4.1",
"acorn-walk": "^8.1.1",
"arg": "^4.1.0",
"create-require": "^1.1.0",
"diff": "^4.0.1",
"make-error": "^1.1.1",
"v8-compile-cache-lib": "^3.0.1",
"yn": "3.1.1"
},
"bin": {
"ts-node": "dist/bin.js",
"ts-node-cwd": "dist/bin-cwd.js",
"ts-node-esm": "dist/bin-esm.js",
"ts-node-script": "dist/bin-script.js",
"ts-node-transpile-only": "dist/bin-transpile.js",
"ts-script": "dist/bin-script-deprecated.js"
},
"peerDependencies": {
"@swc/core": ">=1.2.50",
"@swc/wasm": ">=1.2.50",
"@types/node": "*",
"typescript": ">=2.7"
},
"peerDependenciesMeta": {
"@swc/core": {
"optional": true
},
"@swc/wasm": {
"optional": true
}
}
},
"node_modules/ts-node-dev": {
"version": "2.0.0",
"resolved": "https://registry.npmjs.org/ts-node-dev/-/ts-node-dev-2.0.0.tgz",
"integrity": "sha512-ywMrhCfH6M75yftYvrvNarLEY+SUXtUvU8/0Z6llrHQVBx12GiFk5sStF8UdfE/yfzk9IAq7O5EEbTQsxlBI8w==",
"dev": true,
"license": "MIT",
"dependencies": {
"chokidar": "^3.5.1",
"dynamic-dedupe": "^0.3.0",
"minimist": "^1.2.6",
"mkdirp": "^1.0.4",
"resolve": "^1.0.0",
"rimraf": "^2.6.1",
"source-map-support": "^0.5.12",
"tree-kill": "^1.2.2",
"ts-node": "^10.4.0",
"tsconfig": "^7.0.0"
},
"bin": {
"ts-node-dev": "lib/bin.js",
"tsnd": "lib/bin.js"
},
"engines": {
"node": ">=0.8.0"
},
"peerDependencies": {
"node-notifier": "*",
"typescript": "*"
},
"peerDependenciesMeta": {
"node-notifier": {
"optional": true
}
}
},
"node_modules/ts-node-dev/node_modules/rimraf": {
"version": "2.7.1",
"resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
"integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
"deprecated": "Rimraf versions prior to v4 are no longer supported",
"dev": true,
"license": "ISC",
"dependencies": {
"glob": "^7.1.3"
},
"bin": {
"rimraf": "bin.js"
}
},
"node_modules/tsconfig": {
"version": "7.0.0",
"resolved": "https://registry.npmjs.org/tsconfig/-/tsconfig-7.0.0.tgz",
"integrity": "sha512-vZXmzPrL+EmC4T/4rVlT2jNVMWCi/O4DIiSj3UHg1OE5kCKbk4mfrXc6dZksLgRM/TZlKnousKH9bbTazUWRRw==",
"dev": true,
"license": "MIT",
"dependencies": {
"@types/strip-bom": "^3.0.0",
"@types/strip-json-comments": "0.0.30",
"strip-bom": "^3.0.0",
"strip-json-comments": "^2.0.0"
}
},
"node_modules/tsconfig-paths": {
"version": "4.2.0",
"resolved": "https://registry.npmjs.org/tsconfig-paths/-/tsconfig-paths-4.2.0.tgz",
"integrity": "sha512-NoZ4roiN7LnbKn9QqE1amc9DJfzvZXxF4xDavcOWt1BPkdx+m+0gJuPM+S0vCe7zTJMYUP0R8pO2XMr+Y8oLIg==",
"dev": true,
"license": "MIT",
"dependencies": {
"json5": "^2.2.2",
"minimist": "^1.2.6",
"strip-bom": "^3.0.0"
},
"engines": {
"node": ">=6"
}
},
"node_modules/tsconfig/node_modules/strip-json-comments": {
"version": "2.0.1",
"resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz",
"integrity": "sha512-4gB8na07fecVVkOI6Rs4e7T6NOTki5EmL7TUduTs6bu3EdnSycntVJ4re8kgZA+wx9IueI2Y11bfbgwtzuE0KQ==",
"dev": true,
"license": "MIT",
"engines": {
"node": ">=0.10.0"
}
},
"node_modules/tslib": { "node_modules/tslib": {
"version": "2.8.1", "version": "2.8.1",
"resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz", "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.8.1.tgz",
@ -3797,13 +3323,6 @@
"integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==", "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
"license": "MIT" "license": "MIT"
}, },
"node_modules/v8-compile-cache-lib": {
"version": "3.0.1",
"resolved": "https://registry.npmjs.org/v8-compile-cache-lib/-/v8-compile-cache-lib-3.0.1.tgz",
"integrity": "sha512-wa7YjyUGfNZngI/vtK0UHAN+lgDCxBPCylVXGp0zu59Fz5aiGtNXaq3DhIov063MorB+VfufLh3JlF2KdTK3xg==",
"dev": true,
"license": "MIT"
},
"node_modules/vary": { "node_modules/vary": {
"version": "1.1.2", "version": "1.1.2",
"resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz", "resolved": "https://registry.npmjs.org/vary/-/vary-1.1.2.tgz",
@ -3814,9 +3333,9 @@
} }
}, },
"node_modules/warframe-public-export-plus": { "node_modules/warframe-public-export-plus": {
"version": "0.5.67", "version": "0.5.68",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.67.tgz", "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.68.tgz",
"integrity": "sha512-LsnZD2E5PTA+5MK9kDGvM/hFDtg8sb0EwQ4hKH5ILqrSgz30a9W8785v77RSsL1AEVF8dfb/lZcSTCJq1DZHzQ==" "integrity": "sha512-KMmwCVeQ4k+EN73UZqxnM+qQdPsST8geWoJCP7US5LT6JcRxa8ptmqYXwCzaLtckBLZyVbamsxKZAxPPJckxsA=="
}, },
"node_modules/warframe-riven-info": { "node_modules/warframe-riven-info": {
"version": "0.1.2", "version": "0.1.2",
@ -3931,24 +3450,25 @@
"integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==", "integrity": "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ==",
"license": "ISC" "license": "ISC"
}, },
"node_modules/xtend": { "node_modules/ws": {
"version": "4.0.2", "version": "8.18.2",
"resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.2.tgz", "resolved": "https://registry.npmjs.org/ws/-/ws-8.18.2.tgz",
"integrity": "sha512-LKYU1iAXJXUgAXn9URjiu+MWhyUXHsvfp7mcuYm9dSUKK0/CjtrUwFAxD82/mCWbtLsGjFIad0wIsod4zrTAEQ==", "integrity": "sha512-DMricUmwGZUVr++AEAe2uiVM7UoO9MAVZMDu05UQOaUII0lp+zOzLLU4Xqh/JvTqklB1T4uELaaPBKyjE1r4fQ==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">=0.4" "node": ">=10.0.0"
} },
}, "peerDependencies": {
"node_modules/yn": { "bufferutil": "^4.0.1",
"version": "3.1.1", "utf-8-validate": ">=5.0.2"
"resolved": "https://registry.npmjs.org/yn/-/yn-3.1.1.tgz", },
"integrity": "sha512-Ux4ygGWsu2c7isFWe8Yu1YluJmqVhxqK2cLXNQA5AcC3QfbGNpM7fu0Y8b/z16pXLnFxZYvWhd3fhBY9DLmC6Q==", "peerDependenciesMeta": {
"dev": true, "bufferutil": {
"license": "MIT", "optional": true
"engines": { },
"node": ">=6" "utf-8-validate": {
"optional": true
}
} }
}, },
"node_modules/yocto-queue": { "node_modules/yocto-queue": {

View File

@ -5,8 +5,10 @@
"main": "index.ts", "main": "index.ts",
"scripts": { "scripts": {
"start": "node --enable-source-maps --import ./build/src/pathman.js build/src/index.js", "start": "node --enable-source-maps --import ./build/src/pathman.js build/src/index.js",
"dev": "ts-node-dev --openssl-legacy-provider -r tsconfig-paths/register src/index.ts ",
"build": "tsc --incremental --sourceMap && ncp static/webui build/static/webui", "build": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
"build:dev": "tsc --incremental --sourceMap",
"build-and-start": "npm run build && npm run start",
"dev": "node scripts/dev.js",
"verify": "tsgo --noEmit", "verify": "tsgo --noEmit",
"lint": "eslint --ext .ts .", "lint": "eslint --ext .ts .",
"lint:ci": "eslint --ext .ts --rule \"prettier/prettier: off\" .", "lint:ci": "eslint --ext .ts --rule \"prettier/prettier: off\" .",
@ -18,6 +20,7 @@
"dependencies": { "dependencies": {
"@types/express": "^5", "@types/express": "^5",
"@types/morgan": "^1.9.9", "@types/morgan": "^1.9.9",
"@types/ws": "^8.18.1",
"crc-32": "^1.2.2", "crc-32": "^1.2.2",
"express": "^5", "express": "^5",
"json-with-bigint": "^3.4.4", "json-with-bigint": "^3.4.4",
@ -25,19 +28,20 @@
"morgan": "^1.10.0", "morgan": "^1.10.0",
"ncp": "^2.0.0", "ncp": "^2.0.0",
"typescript": "^5.5", "typescript": "^5.5",
"warframe-public-export-plus": "^0.5.67", "warframe-public-export-plus": "^0.5.68",
"warframe-riven-info": "^0.1.2", "warframe-riven-info": "^0.1.2",
"winston": "^3.17.0", "winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0" "winston-daily-rotate-file": "^5.0.0",
"ws": "^8.18.2"
}, },
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.28.0", "@typescript-eslint/eslint-plugin": "^8.28.0",
"@typescript-eslint/parser": "^8.28.0", "@typescript-eslint/parser": "^8.28.0",
"@typescript/native-preview": "^7.0.0-dev.20250523.1", "@typescript/native-preview": "^7.0.0-dev.20250523.1",
"chokidar": "^4.0.3",
"eslint": "^8", "eslint": "^8",
"eslint-plugin-prettier": "^5.2.5", "eslint-plugin-prettier": "^5.2.5",
"prettier": "^3.5.3", "prettier": "^3.5.3",
"ts-node-dev": "^2.0.0", "tree-kill": "^1.2.2"
"tsconfig-paths": "^4.2.0"
} }
} }

55
scripts/dev.js Normal file
View File

@ -0,0 +1,55 @@
/* eslint-disable */
const { spawn } = require("child_process");
const chokidar = require("chokidar");
const kill = require("tree-kill");
let secret = "";
for (let i = 0; i != 10; ++i) {
secret += String.fromCharCode(Math.floor(Math.random() * 26) + 0x41);
}
const args = [...process.argv].splice(2);
args.push("--dev");
args.push("--secret");
args.push(secret);
let buildproc, runproc;
function run(changedFile) {
if (changedFile) {
console.log(`Change to ${changedFile} detected`);
}
if (buildproc) {
kill(buildproc.pid);
buildproc = undefined;
}
if (runproc) {
kill(runproc.pid);
runproc = undefined;
}
const thisbuildproc = spawn("npm", ["run", "build:dev"], { stdio: "inherit", shell: true });
buildproc = thisbuildproc;
buildproc.on("exit", code => {
if (buildproc !== thisbuildproc) {
return;
}
buildproc = undefined;
if (code === 0) {
runproc = spawn("npm", ["run", "start", "--", ...args], { stdio: "inherit", shell: true });
runproc.on("exit", () => {
runproc = undefined;
});
}
});
}
run();
chokidar.watch("src").on("change", run);
chokidar.watch("static/fixed_responses").on("change", run);
chokidar.watch("static/webui").on("change", async () => {
try {
await fetch("http://localhost/custom/webuiFileChangeDetected?secret=" + secret);
} catch (e) {}
});

View File

@ -1,6 +1,7 @@
// Based on https://onlyg.it/OpenWF/Translations/src/branch/main/update.php // Based on https://onlyg.it/OpenWF/Translations/src/branch/main/update.php
// Converted via ChatGPT-4o // Converted via ChatGPT-4o
/* eslint-disable */
const fs = require("fs"); const fs = require("fs");
function extractStrings(content) { function extractStrings(content) {

View File

@ -0,0 +1,107 @@
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { addMiscItems, freeUpSlot, getInventory, updateCurrency } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { IOid } from "@/src/types/commonTypes";
import { ICrewShipComponentFingerprint, InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { RequestHandler } from "express";
import { ExportCustoms, ExportDojoRecipes } from "warframe-public-export-plus";
export const crewShipFusionController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId);
const payload = getJSONfromString<ICrewShipFusionRequest>(String(req.body));
const isWeapon = inventory.CrewShipWeapons.id(payload.PartA.$oid);
const itemA = isWeapon ?? inventory.CrewShipWeaponSkins.id(payload.PartA.$oid)!;
const category = isWeapon ? "CrewShipWeapons" : "CrewShipWeaponSkins";
const salvageCategory = isWeapon ? "CrewShipSalvagedWeapons" : "CrewShipSalvagedWeaponSkins";
const itemB = inventory[payload.SourceRecipe ? salvageCategory : category].id(payload.PartB.$oid)!;
const tierA = itemA.ItemType.charCodeAt(itemA.ItemType.length - 1) - 65;
const tierB = itemB.ItemType.charCodeAt(itemB.ItemType.length - 1) - 65;
const inventoryChanges: IInventoryChanges = {};
// Charge partial repair cost if fusing with an identified but unrepaired part
if (payload.SourceRecipe) {
const recipe = ExportDojoRecipes.research[payload.SourceRecipe];
updateCurrency(inventory, Math.round(recipe.price * 0.4), false, inventoryChanges);
const miscItemChanges = recipe.ingredients.map(x => ({ ...x, ItemCount: Math.round(x.ItemCount * -0.4) }));
addMiscItems(inventory, miscItemChanges);
inventoryChanges.MiscItems = miscItemChanges;
}
// Remove inferior item
if (payload.SourceRecipe) {
inventory[salvageCategory].pull({ _id: payload.PartB.$oid });
inventoryChanges.RemovedIdItems = [{ ItemId: payload.PartB }];
} else {
const inferiorId = tierA < tierB ? payload.PartA : payload.PartB;
inventory[category].pull({ _id: inferiorId.$oid });
inventoryChanges.RemovedIdItems = [{ ItemId: inferiorId }];
freeUpSlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS);
inventoryChanges[InventorySlot.RJ_COMPONENT_AND_ARMAMENTS] = { count: -1, platinum: 0, Slots: 1 };
}
// Upgrade superior item
const superiorItem = tierA < tierB ? itemB : itemA;
const inferiorItem = tierA < tierB ? itemA : itemB;
const fingerprint: ICrewShipComponentFingerprint = JSON.parse(
superiorItem.UpgradeFingerprint!
) as ICrewShipComponentFingerprint;
const inferiorFingerprint: ICrewShipComponentFingerprint = inferiorItem.UpgradeFingerprint
? (JSON.parse(inferiorItem.UpgradeFingerprint) as ICrewShipComponentFingerprint)
: { compat: "", buffs: [] };
if (isWeapon) {
for (let i = 0; i != fingerprint.buffs.length; ++i) {
const buffA = fingerprint.buffs[i];
const buffB = i < inferiorFingerprint.buffs.length ? inferiorFingerprint.buffs[i] : undefined;
const fvalA = buffA.Value / 0x3fffffff;
const fvalB = (buffB?.Value ?? 0) / 0x3fffffff;
const percA = 0.3 + fvalA * (0.6 - 0.3);
const percB = 0.3 + fvalB * (0.6 - 0.3);
const newPerc = Math.min(0.6, Math.max(percA, percB) * FUSE_MULTIPLIERS[Math.abs(tierA - tierB)]);
const newFval = (newPerc - 0.3) / (0.6 - 0.3);
buffA.Value = Math.trunc(newFval * 0x3fffffff);
}
} else {
const superiorMeta = ExportCustoms[superiorItem.ItemType].randomisedUpgrades ?? [];
const inferiorMeta = ExportCustoms[inferiorItem.ItemType].randomisedUpgrades ?? [];
for (let i = 0; i != inferiorFingerprint.buffs.length; ++i) {
const buffA = fingerprint.buffs[i];
const buffB = inferiorFingerprint.buffs[i];
const fvalA = buffA.Value / 0x3fffffff;
const fvalB = buffB.Value / 0x3fffffff;
const rangeA = superiorMeta[i].range;
const rangeB = inferiorMeta[i].range;
const percA = rangeA[0] + fvalA * (rangeA[1] - rangeA[0]);
const percB = rangeB[0] + fvalB * (rangeB[1] - rangeB[0]);
const newPerc = Math.min(rangeA[1], Math.max(percA, percB) * FUSE_MULTIPLIERS[Math.abs(tierA - tierB)]);
const newFval = (newPerc - rangeA[0]) / (rangeA[1] - rangeA[0]);
buffA.Value = Math.trunc(newFval * 0x3fffffff);
}
if (inferiorFingerprint.SubroutineIndex) {
const useSuperiorSubroutine = tierA < tierB ? !payload.UseSubroutineA : payload.UseSubroutineA;
if (!useSuperiorSubroutine) {
fingerprint.SubroutineIndex = inferiorFingerprint.SubroutineIndex;
}
}
}
superiorItem.UpgradeFingerprint = JSON.stringify(fingerprint);
// eslint-disable-next-line @typescript-eslint/no-explicit-any
inventoryChanges[category] = [superiorItem.toJSON() as any];
await inventory.save();
res.json({
InventoryChanges: inventoryChanges
});
};
interface ICrewShipFusionRequest {
PartA: IOid;
PartB: IOid;
SourceRecipe: string;
UseSubroutineA: boolean;
}
const FUSE_MULTIPLIERS = [1.1, 1.05, 1.02];

View File

@ -43,7 +43,7 @@ export const focusController: RequestHandler = async (req, res) => {
inventory.FocusAbility ??= focusType; inventory.FocusAbility ??= focusType;
inventory.FocusUpgrades.push({ ItemType: focusType }); inventory.FocusUpgrades.push({ ItemType: focusType });
if (inventory.FocusXP) { if (inventory.FocusXP) {
inventory.FocusXP[focusPolarity] -= cost; inventory.FocusXP[focusPolarity]! -= cost;
} }
await inventory.save(); await inventory.save();
res.json({ res.json({
@ -78,7 +78,7 @@ export const focusController: RequestHandler = async (req, res) => {
cost += ExportFocusUpgrades[focusType].baseFocusPointCost; cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 }); inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
} }
inventory.FocusXP![focusPolarity] -= cost; inventory.FocusXP![focusPolarity]! -= cost;
await inventory.save(); await inventory.save();
res.json({ res.json({
FocusTypes: request.FocusTypes, FocusTypes: request.FocusTypes,
@ -96,7 +96,7 @@ export const focusController: RequestHandler = async (req, res) => {
const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!; const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
focusUpgradeDb.Level = focusUpgrade.Level; focusUpgradeDb.Level = focusUpgrade.Level;
} }
inventory.FocusXP![focusPolarity] -= cost; inventory.FocusXP![focusPolarity]! -= cost;
await inventory.save(); await inventory.save();
res.json({ res.json({
FocusInfos: request.FocusInfos, FocusInfos: request.FocusInfos,
@ -123,7 +123,7 @@ export const focusController: RequestHandler = async (req, res) => {
const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest; const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]); const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
inventory.FocusXP![focusPolarity] -= 750_000 * request.FocusTypes.length; inventory.FocusXP![focusPolarity]! -= 750_000 * request.FocusTypes.length;
addMiscItems(inventory, [ addMiscItems(inventory, [
{ {
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem", ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem",
@ -168,8 +168,10 @@ export const focusController: RequestHandler = async (req, res) => {
shard.ItemCount *= -1; shard.ItemCount *= -1;
} }
const inventory = await getInventory(accountId); const inventory = await getInventory(accountId);
inventory.FocusXP ??= { AP_POWER: 0, AP_TACTIC: 0, AP_DEFENSE: 0, AP_ATTACK: 0, AP_WARD: 0 }; const polarity = request.Polarity;
inventory.FocusXP[request.Polarity] += xp; inventory.FocusXP ??= {};
inventory.FocusXP[polarity] ??= 0;
inventory.FocusXP[polarity] += xp;
addMiscItems(inventory, request.Shards); addMiscItems(inventory, request.Shards);
await inventory.save(); await inventory.save();
break; break;

View File

@ -11,7 +11,7 @@ import {
scaleRequiredCount, scaleRequiredCount,
setGuildTechLogState setGuildTechLogState
} from "@/src/services/guildService"; } from "@/src/services/guildService";
import { ExportDojoRecipes } from "warframe-public-export-plus"; import { ExportDojoRecipes, ExportRailjackWeapons } from "warframe-public-export-plus";
import { getAccountIdForRequest } from "@/src/services/loginService"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { import {
addCrewShipWeaponSkin, addCrewShipWeaponSkin,
@ -442,6 +442,7 @@ const finishComponentRepair = (
...(category == "CrewShipWeaponSkins" ...(category == "CrewShipWeaponSkins"
? addCrewShipWeaponSkin(inventory, salvageItem.ItemType, salvageItem.UpgradeFingerprint) ? addCrewShipWeaponSkin(inventory, salvageItem.ItemType, salvageItem.UpgradeFingerprint)
: addEquipment(inventory, category, salvageItem.ItemType, { : addEquipment(inventory, category, salvageItem.ItemType, {
UpgradeType: ExportRailjackWeapons[salvageItem.ItemType].defaultUpgrades?.[0].ItemType,
UpgradeFingerprint: salvageItem.UpgradeFingerprint UpgradeFingerprint: salvageItem.UpgradeFingerprint
})), })),
...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, false) ...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, false)

View File

@ -30,8 +30,9 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
const request = getJSONfromString<IShardInstallRequest>(String(req.body)); const request = getJSONfromString<IShardInstallRequest>(String(req.body));
const inventory = await getInventory(account._id.toString()); const inventory = await getInventory(account._id.toString());
const suit = inventory.Suits.id(request.SuitId.$oid)!; const suit = inventory.Suits.id(request.SuitId.$oid)!;
if (!suit.ArchonCrystalUpgrades || suit.ArchonCrystalUpgrades.length != 5) { suit.ArchonCrystalUpgrades ??= [];
suit.ArchonCrystalUpgrades = [{}, {}, {}, {}, {}]; while (suit.ArchonCrystalUpgrades.length < request.Slot) {
suit.ArchonCrystalUpgrades.push({});
} }
suit.ArchonCrystalUpgrades[request.Slot] = { suit.ArchonCrystalUpgrades[request.Slot] = {
UpgradeType: request.UpgradeType, UpgradeType: request.UpgradeType,
@ -92,7 +93,8 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
} }
// remove from suit // remove from suit
suit.ArchonCrystalUpgrades![request.Slot] = {}; suit.ArchonCrystalUpgrades![request.Slot].UpgradeType = undefined;
suit.ArchonCrystalUpgrades![request.Slot].Color = undefined;
await inventory.save(); await inventory.save();

View File

@ -339,9 +339,29 @@ export const getInventoryResponse = async (
} }
} }
if (config.unlockAllProfitTakerStages) {
inventoryResponse.CompletedJobChains ??= [];
const EudicoHeists = inventoryResponse.CompletedJobChains.find(x => x.LocationTag == "EudicoHeists");
if (EudicoHeists) {
EudicoHeists.Jobs = allEudicoHeistJobs;
} else {
inventoryResponse.CompletedJobChains.push({
LocationTag: "EudicoHeists",
Jobs: allEudicoHeistJobs
});
}
}
return inventoryResponse; return inventoryResponse;
}; };
const allEudicoHeistJobs = [
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyOne",
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyTwo",
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyThree",
"/Lotus/Types/Gameplay/Venus/Jobs/Heists/HeistProfitTakerBountyFour"
];
const addString = (arr: string[], str: string): void => { const addString = (arr: string[], str: string): void => {
if (arr.indexOf(str) == -1) { if (arr.indexOf(str) == -1) {
arr.push(str); arr.push(str);

View File

@ -4,16 +4,16 @@ import { config } from "@/src/services/configService";
import { buildConfig } from "@/src/services/buildConfigService"; import { buildConfig } from "@/src/services/buildConfigService";
import { Account } from "@/src/models/loginModel"; import { Account } from "@/src/models/loginModel";
import { createAccount, isCorrectPassword, isNameTaken } from "@/src/services/loginService"; import { createAccount, createNonce, getUsernameFromEmail, isCorrectPassword } from "@/src/services/loginService";
import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes"; import { IDatabaseAccountJson, ILoginRequest, ILoginResponse } from "@/src/types/loginTypes";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { version_compare } from "@/src/helpers/inventoryHelpers"; import { version_compare } from "@/src/helpers/inventoryHelpers";
import { sendWsBroadcastTo } from "@/src/services/webService";
export const loginController: RequestHandler = async (request, response) => { export const loginController: RequestHandler = async (request, response) => {
const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object const loginRequest = JSON.parse(String(request.body)) as ILoginRequest; // parse octet stream of json data to json object
const account = await Account.findOne({ email: loginRequest.email }); const account = await Account.findOne({ email: loginRequest.email });
const nonce = Math.round(Math.random() * Number.MAX_SAFE_INTEGER);
const buildLabel: string = const buildLabel: string =
typeof request.query.buildLabel == "string" typeof request.query.buildLabel == "string"
@ -42,26 +42,14 @@ export const loginController: RequestHandler = async (request, response) => {
loginRequest.ClientType == "webui-register") loginRequest.ClientType == "webui-register")
) { ) {
try { try {
const nameFromEmail = loginRequest.email.substring(0, loginRequest.email.indexOf("@")); const name = await getUsernameFromEmail(loginRequest.email);
let name = nameFromEmail || loginRequest.email.substring(1) || "SpaceNinja";
if (await isNameTaken(name)) {
let suffix = 0;
do {
++suffix;
name = nameFromEmail + suffix;
} while (await isNameTaken(name));
}
const newAccount = await createAccount({ const newAccount = await createAccount({
email: loginRequest.email, email: loginRequest.email,
password: loginRequest.password, password: loginRequest.password,
DisplayName: name, DisplayName: name,
CountryCode: loginRequest.lang?.toUpperCase() ?? "EN", CountryCode: loginRequest.lang?.toUpperCase() ?? "EN",
ClientType: loginRequest.ClientType == "webui-register" ? "webui" : loginRequest.ClientType, ClientType: loginRequest.ClientType,
CrossPlatformAllowed: true, Nonce: createNonce(),
ForceLogoutVersion: 0,
ConsentNeeded: false,
TrackedSettings: [],
Nonce: nonce,
BuildLabel: buildLabel, BuildLabel: buildLabel,
LastLogin: new Date() LastLogin: new Date()
}); });
@ -80,38 +68,29 @@ export const loginController: RequestHandler = async (request, response) => {
return; return;
} }
if (loginRequest.ClientType == "webui-register") {
response.status(400).json({ error: "account already exists" });
return;
}
if (!isCorrectPassword(loginRequest.password, account.password)) { if (!isCorrectPassword(loginRequest.password, account.password)) {
response.status(400).json({ error: "incorrect login data" }); response.status(400).json({ error: "incorrect login data" });
return; return;
} }
if (loginRequest.ClientType == "webui") { if (account.Nonce && account.ClientType != "webui" && !account.Dropped && !loginRequest.kick) {
if (!account.Nonce) { // U17 seems to handle "nonce still set" like a login failure.
account.ClientType = "webui"; if (version_compare(buildLabel, "2015.12.05.18.07") >= 0) {
account.Nonce = nonce; response.status(400).send({ error: "nonce still set" });
return;
} }
} else {
if (account.Nonce && account.ClientType != "webui" && !account.Dropped && !loginRequest.kick) {
// U17 seems to handle "nonce still set" like a login failure.
if (version_compare(buildLabel, "2015.12.05.18.07") >= 0) {
response.status(400).send({ error: "nonce still set" });
return;
}
}
account.ClientType = loginRequest.ClientType;
account.Nonce = nonce;
account.CountryCode = loginRequest.lang?.toUpperCase() ?? "EN";
account.BuildLabel = buildLabel;
account.LastLogin = new Date();
} }
account.ClientType = loginRequest.ClientType;
account.Nonce = createNonce();
account.CountryCode = loginRequest.lang?.toUpperCase() ?? "EN";
account.BuildLabel = buildLabel;
account.LastLogin = new Date();
await account.save(); await account.save();
// Tell WebUI its nonce has been invalidated
sendWsBroadcastTo(account._id.toString(), { logged_out: true });
response.json(createLoginResponse(myAddress, myUrlBase, account.toJSON(), buildLabel)); response.json(createLoginResponse(myAddress, myUrlBase, account.toJSON(), buildLabel));
}; };

View File

@ -1,5 +1,6 @@
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { Account } from "@/src/models/loginModel"; import { Account } from "@/src/models/loginModel";
import { sendWsBroadcastTo } from "@/src/services/webService";
export const logoutController: RequestHandler = async (req, res) => { export const logoutController: RequestHandler = async (req, res) => {
if (!req.query.accountId) { if (!req.query.accountId) {
@ -10,7 +11,7 @@ export const logoutController: RequestHandler = async (req, res) => {
throw new Error("Request is missing nonce parameter"); throw new Error("Request is missing nonce parameter");
} }
await Account.updateOne( const stat = await Account.updateOne(
{ {
_id: req.query.accountId, _id: req.query.accountId,
Nonce: nonce Nonce: nonce
@ -19,6 +20,10 @@ export const logoutController: RequestHandler = async (req, res) => {
Nonce: 0 Nonce: 0
} }
); );
if (stat.modifiedCount) {
// Tell WebUI its nonce has been invalidated
sendWsBroadcastTo(req.query.accountId as string, { logged_out: true });
}
res.writeHead(200, { res.writeHead(200, {
"Content-Type": "text/html", "Content-Type": "text/html",

View File

@ -1,5 +1,6 @@
import { version_compare } from "@/src/helpers/inventoryHelpers"; import { version_compare } from "@/src/helpers/inventoryHelpers";
import { import {
antivirusMods,
consumeModCharge, consumeModCharge,
decodeNemesisGuess, decodeNemesisGuess,
encodeNemesisGuess, encodeNemesisGuess,
@ -16,6 +17,7 @@ import {
IKnifeResponse IKnifeResponse
} from "@/src/helpers/nemesisHelpers"; } from "@/src/helpers/nemesisHelpers";
import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
import { Loadout } from "@/src/models/inventoryModels/loadoutModel"; import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
import { freeUpSlot, getInventory } from "@/src/services/inventoryService"; import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
import { getAccountForRequest } from "@/src/services/loginService"; import { getAccountForRequest } from "@/src/services/loginService";
@ -134,34 +136,38 @@ export const nemesisController: RequestHandler = async (req, res) => {
for (const upgrade of body.knife!.AttachedUpgrades) { for (const upgrade of body.knife!.AttachedUpgrades) {
switch (upgrade.ItemType) { switch (upgrade.ItemType) {
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod": case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
antivirusGain += 10;
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
break;
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod": case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod":
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
antivirusGain += 10; antivirusGain += 10;
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
break; break;
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure
antivirusGain += 15;
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
break;
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield
antivirusGain += 15; antivirusGain += 15;
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades); consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
break; break;
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
antivirusGain += 10;
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
break;
} }
} }
inventory.Nemesis!.HenchmenKilled += antivirusGain; inventory.Nemesis!.HenchmenKilled += antivirusGain;
if (inventory.Nemesis!.HenchmenKilled >= 100) {
inventory.Nemesis!.HenchmenKilled = 100;
// Weaken nemesis now.
inventory.Nemesis!.InfNodes = [
{
Node: getNemesisManifest(inventory.Nemesis!.manifest).showdownNode,
Influence: 1
}
];
inventory.Nemesis!.Weakened = true;
const upgrade = getKnifeUpgrade(inventory, dataknifeUpgrades, antivirusMods[passcode]);
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
}
} }
if (inventory.Nemesis!.HenchmenKilled >= 100) { if (inventory.Nemesis!.HenchmenKilled < 100) {
inventory.Nemesis!.HenchmenKilled = 100; inventory.Nemesis!.InfNodes = getInfNodes(getNemesisManifest(inventory.Nemesis!.manifest), 0);
} }
inventory.Nemesis!.InfNodes = getInfNodes(getNemesisManifest(inventory.Nemesis!.manifest), 0);
await inventory.save(); await inventory.save();
res.json(response); res.json(response);
@ -198,16 +204,28 @@ export const nemesisController: RequestHandler = async (req, res) => {
guess[body.position].result = correct ? GUESS_CORRECT : GUESS_INCORRECT; guess[body.position].result = correct ? GUESS_CORRECT : GUESS_INCORRECT;
inventory.Nemesis!.GuessHistory[inventory.Nemesis!.GuessHistory.length - 1] = encodeNemesisGuess(guess); inventory.Nemesis!.GuessHistory[inventory.Nemesis!.GuessHistory.length - 1] = encodeNemesisGuess(guess);
// Increase rank if incorrect const response: INemesisRequiemResponse = {};
let RankIncrease: number | undefined; if (correct) {
if (!correct) { if (body.position == 2) {
RankIncrease = 1; // That was all 3 guesses correct, nemesis is now weakened.
inventory.Nemesis!.InfNodes = [
{
Node: getNemesisManifest(inventory.Nemesis!.manifest).showdownNode,
Influence: 1
}
];
inventory.Nemesis!.Weakened = true;
await consumePasscodeModCharges(inventory, response);
}
} else {
// Guess was incorrect, increase rank
response.RankIncrease = 1;
const manifest = getNemesisManifest(inventory.Nemesis!.manifest); const manifest = getNemesisManifest(inventory.Nemesis!.manifest);
inventory.Nemesis!.Rank = Math.min(inventory.Nemesis!.Rank + 1, manifest.systemIndexes.length - 1); inventory.Nemesis!.Rank = Math.min(inventory.Nemesis!.Rank + 1, manifest.systemIndexes.length - 1);
inventory.Nemesis!.InfNodes = getInfNodes(manifest, inventory.Nemesis!.Rank); inventory.Nemesis!.InfNodes = getInfNodes(manifest, inventory.Nemesis!.Rank);
} }
await inventory.save(); await inventory.save();
res.json({ RankIncrease }); res.json(response);
} }
} else if ((req.query.mode as string) == "rs") { } else if ((req.query.mode as string) == "rs") {
// report spawn; POST but no application data in body // report spawn; POST but no application data in body
@ -277,36 +295,15 @@ export const nemesisController: RequestHandler = async (req, res) => {
target: inventory.toJSON().Nemesis target: inventory.toJSON().Nemesis
}); });
} else if ((req.query.mode as string) == "w") { } else if ((req.query.mode as string) == "w") {
const inventory = await getInventory( const inventory = await getInventory(account._id.toString(), "Nemesis");
account._id.toString(),
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
);
//const body = getJSONfromString<INemesisWeakenRequest>(String(req.body)); //const body = getJSONfromString<INemesisWeakenRequest>(String(req.body));
inventory.Nemesis!.InfNodes = [ // As of 38.6.0, this request is no longer sent, instead mode=r already weakens the nemesis if appropriate.
{ // We always weaken the nemesis in mode=r so simply giving the client back the nemesis.
Node: getNemesisManifest(inventory.Nemesis!.manifest).showdownNode,
Influence: 1
}
];
inventory.Nemesis!.Weakened = true;
const response: IKnifeResponse & { target: INemesisClient } = { const response: INemesisWeakenResponse = {
target: inventory.toJSON<IInventoryClient>().Nemesis! target: inventory.toJSON<IInventoryClient>().Nemesis!
}; };
// Consume charge of the correct requiem mod(s)
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
const modTypes = getNemesisPasscodeModTypes(inventory.Nemesis!);
for (const modType of modTypes) {
const upgrade = getKnifeUpgrade(inventory, dataknifeUpgrades, modType);
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
}
await inventory.save();
res.json(response); res.json(response);
} else { } else {
logger.debug(`data provided to ${req.path}: ${String(req.body)}`); logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
@ -362,11 +359,19 @@ interface INemesisRequiemRequest {
knife?: IKnife; knife?: IKnife;
} }
interface INemesisRequiemResponse extends IKnifeResponse {
RankIncrease?: number;
}
// interface INemesisWeakenRequest { // interface INemesisWeakenRequest {
// target: INemesisClient; // target: INemesisClient;
// knife: IKnife; // knife: IKnife;
// } // }
interface INemesisWeakenResponse extends IKnifeResponse {
target: INemesisClient;
}
interface IKnife { interface IKnife {
Item: IEquipmentClient; Item: IEquipmentClient;
Skins: IWeaponSkinClient[]; Skins: IWeaponSkinClient[];
@ -375,3 +380,18 @@ interface IKnife {
AttachedUpgrades: IUpgradeClient[]; AttachedUpgrades: IUpgradeClient[];
HiddenWhenHolstered: boolean; HiddenWhenHolstered: boolean;
} }
const consumePasscodeModCharges = async (
inventory: TInventoryDatabaseDocument,
response: IKnifeResponse
): Promise<void> => {
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
const modTypes = getNemesisPasscodeModTypes(inventory.Nemesis!);
for (const modType of modTypes) {
const upgrade = getKnifeUpgrade(inventory, dataknifeUpgrades, modType);
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
}
};

View File

@ -1,6 +1,7 @@
import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { getInventory, updateCurrency } from "@/src/services/inventoryService"; import { getInventory, updateCurrency } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService"; import { getAccountIdForRequest } from "@/src/services/loginService";
import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { RequestHandler } from "express"; import { RequestHandler } from "express";
export const renamePetController: RequestHandler = async (req, res) => { export const renamePetController: RequestHandler = async (req, res) => {
@ -8,12 +9,18 @@ export const renamePetController: RequestHandler = async (req, res) => {
const inventory = await getInventory(accountId, "KubrowPets PremiumCredits PremiumCreditsFree"); const inventory = await getInventory(accountId, "KubrowPets PremiumCredits PremiumCreditsFree");
const data = getJSONfromString<IRenamePetRequest>(String(req.body)); const data = getJSONfromString<IRenamePetRequest>(String(req.body));
const details = inventory.KubrowPets.id(data.petId)!.Details!; const details = inventory.KubrowPets.id(data.petId)!.Details!;
details.Name = data.name; details.Name = data.name;
const currencyChanges = updateCurrency(inventory, 15, true);
const inventoryChanges: IInventoryChanges = {};
if (!("webui" in req.query)) {
updateCurrency(inventory, 15, true, inventoryChanges);
}
await inventory.save(); await inventory.save();
res.json({ res.json({
...data, ...data,
inventoryChanges: currencyChanges inventoryChanges: inventoryChanges
}); });
}; };

View File

@ -0,0 +1,22 @@
import { fromMongoDate, fromOid } from "@/src/helpers/inventoryHelpers";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { RequestHandler } from "express";
export const setSuitInfectionController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId, "Suits");
const payload = getJSONfromString<ISetSuitInfectionRequest>(String(req.body));
for (const clientSuit of payload.Suits) {
const dbSuit = inventory.Suits.id(fromOid(clientSuit.ItemId))!;
dbSuit.InfestationDate = fromMongoDate(clientSuit.InfestationDate!);
}
await inventory.save();
res.end();
};
interface ISetSuitInfectionRequest {
Suits: IEquipmentClient[];
}

View File

@ -0,0 +1,27 @@
import { fromMongoDate, fromOid } from "@/src/helpers/inventoryHelpers";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { addMiscItem, getInventory } from "@/src/services/inventoryService";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
import { RequestHandler } from "express";
export const umbraController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
const inventory = await getInventory(accountId, "Suits MiscItems");
const payload = getJSONfromString<IUmbraRequest>(String(req.body));
for (const clientSuit of payload.Suits) {
const dbSuit = inventory.Suits.id(fromOid(clientSuit.ItemId))!;
if (clientSuit.UmbraDate) {
addMiscItem(inventory, "/Lotus/Types/Items/MiscItems/UmbraEchoes", -1);
dbSuit.UmbraDate = fromMongoDate(clientSuit.UmbraDate);
} else {
dbSuit.UmbraDate = undefined;
}
}
await inventory.save();
res.end();
};
interface IUmbraRequest {
Suits: IEquipmentClient[];
}

View File

@ -4,6 +4,8 @@ import { getAccountForRequest } from "@/src/services/loginService";
import { addChallenges, getInventory } from "@/src/services/inventoryService"; import { addChallenges, getInventory } from "@/src/services/inventoryService";
import { IChallengeProgress, ISeasonChallenge } from "@/src/types/inventoryTypes/inventoryTypes"; import { IChallengeProgress, ISeasonChallenge } from "@/src/types/inventoryTypes/inventoryTypes";
import { IAffiliationMods } from "@/src/types/purchaseTypes"; import { IAffiliationMods } from "@/src/types/purchaseTypes";
import { getEntriesUnsafe } from "@/src/utils/ts-utils";
import { logger } from "@/src/utils/logger";
export const updateChallengeProgressController: RequestHandler = async (req, res) => { export const updateChallengeProgressController: RequestHandler = async (req, res) => {
const challenges = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body)); const challenges = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body));
@ -11,7 +13,7 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
const inventory = await getInventory( const inventory = await getInventory(
account._id.toString(), account._id.toString(),
"ChallengeProgress SeasonChallengeHistory Affiliations" "ChallengesFixVersion ChallengeProgress SeasonChallengeHistory Affiliations"
); );
let affiliationMods: IAffiliationMods[] = []; let affiliationMods: IAffiliationMods[] = [];
if (challenges.ChallengeProgress) { if (challenges.ChallengeProgress) {
@ -22,15 +24,31 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
challenges.SeasonChallengeCompletions challenges.SeasonChallengeCompletions
); );
} }
if (challenges.SeasonChallengeHistory) { for (const [key, value] of getEntriesUnsafe(challenges)) {
challenges.SeasonChallengeHistory.forEach(({ challenge, id }) => { switch (key) {
const itemIndex = inventory.SeasonChallengeHistory.findIndex(i => i.challenge === challenge); case "ChallengesFixVersion":
if (itemIndex !== -1) { inventory.ChallengesFixVersion = value;
inventory.SeasonChallengeHistory[itemIndex].id = id; break;
} else {
inventory.SeasonChallengeHistory.push({ challenge, id }); case "SeasonChallengeHistory":
} value!.forEach(({ challenge, id }) => {
}); const itemIndex = inventory.SeasonChallengeHistory.findIndex(i => i.challenge === challenge);
if (itemIndex !== -1) {
inventory.SeasonChallengeHistory[itemIndex].id = id;
} else {
inventory.SeasonChallengeHistory.push({ challenge, id });
}
});
break;
case "ChallengeProgress":
case "SeasonChallengeCompletions":
case "ChallengePTS":
case "crossPlaySetting":
break;
default:
logger.warn(`unknown challenge progress entry`, { key, value });
}
} }
await inventory.save(); await inventory.save();
@ -40,7 +58,10 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
}; };
interface IUpdateChallengeProgressRequest { interface IUpdateChallengeProgressRequest {
ChallengePTS?: number;
ChallengesFixVersion?: number;
ChallengeProgress?: IChallengeProgress[]; ChallengeProgress?: IChallengeProgress[];
SeasonChallengeHistory?: ISeasonChallenge[]; SeasonChallengeHistory?: ISeasonChallenge[];
SeasonChallengeCompletions?: ISeasonChallenge[]; SeasonChallengeCompletions?: ISeasonChallenge[];
crossPlaySetting?: string;
} }

View File

@ -12,6 +12,7 @@ export const popArchonCrystalUpgradeController: RequestHandler = async (req, res
); );
await inventory.save(); await inventory.save();
res.end(); res.end();
return;
} }
res.status(400).end(); res.status(400).end();
}; };

View File

@ -15,6 +15,7 @@ export const pushArchonCrystalUpgradeController: RequestHandler = async (req, re
} }
await inventory.save(); await inventory.save();
res.end(); res.end();
return;
} }
} }
res.status(400).end(); res.status(400).end();

View File

@ -1,15 +1,21 @@
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { updateConfig } from "@/src/services/configWatcherService"; import { saveConfig } from "@/src/services/configWatcherService";
import { getAccountForRequest, isAdministrator } from "@/src/services/loginService"; import { getAccountForRequest, isAdministrator } from "@/src/services/loginService";
import { config, IConfig } from "@/src/services/configService";
const updateConfigDataController: RequestHandler = async (req, res) => { export const updateConfigDataController: RequestHandler = async (req, res) => {
const account = await getAccountForRequest(req); const account = await getAccountForRequest(req);
if (isAdministrator(account)) { if (isAdministrator(account)) {
await updateConfig(String(req.body)); const data = req.body as IUpdateConfigDataRequest;
config[data.key] = data.value;
await saveConfig();
res.end(); res.end();
} else { } else {
res.status(401).end(); res.status(401).end();
} }
}; };
export { updateConfigDataController }; interface IUpdateConfigDataRequest {
key: keyof IConfig;
value: never;
}

View File

@ -0,0 +1,10 @@
import { args } from "@/src/helpers/commandLineArguments";
import { sendWsBroadcast } from "@/src/services/webService";
import { RequestHandler } from "express";
export const webuiFileChangeDetectedController: RequestHandler = (req, res) => {
if (args.dev && args.secret && req.query.secret == args.secret) {
sendWsBroadcast({ reload: true });
}
res.end();
};

View File

@ -1,6 +1,15 @@
import { RequestHandler } from "express"; import { RequestHandler } from "express";
import { getWorldState } from "@/src/services/worldStateService"; import { getWorldState, populateFissures } from "@/src/services/worldStateService";
import { version_compare } from "@/src/helpers/inventoryHelpers";
export const worldStateController: RequestHandler = (req, res) => { export const worldStateController: RequestHandler = async (req, res) => {
res.json(getWorldState(req.query.buildLabel as string | undefined)); const buildLabel = req.query.buildLabel as string | undefined;
const worldState = getWorldState(buildLabel);
// Omitting void fissures for versions prior to Dante Unbound to avoid script errors.
if (!buildLabel || version_compare(buildLabel, "2024.03.24.20.00") >= 0) {
await populateFissures(worldState);
}
res.json(worldState);
}; };

View File

@ -0,0 +1,23 @@
interface IArguments {
configPath?: string;
dev?: boolean;
secret?: string;
}
export const args: IArguments = {};
for (let i = 2; i < process.argv.length; ) {
switch (process.argv[i++]) {
case "--configPath":
args.configPath = process.argv[i++];
break;
case "--dev":
args.dev = true;
break;
case "--secret":
args.secret = process.argv[i++];
break;
}
}

View File

@ -248,7 +248,7 @@ const requiemMods: readonly string[] = [
"/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod" "/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod"
]; ];
const antivirusMods: readonly string[] = [ export const antivirusMods: readonly string[] = [
"/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod", "/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
"/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod", "/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod",
"/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod", "/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod",

View File

@ -1,5 +1,4 @@
import path from "path"; import path from "path";
export const rootDir = path.join(__dirname, "../.."); export const rootDir = path.join(__dirname, "../..");
export const isDev = path.basename(rootDir) != "build"; export const repoDir = path.basename(rootDir) != "build" ? rootDir : path.join(rootDir, "..");
export const repoDir = isDev ? rootDir : path.join(rootDir, "..");

View File

@ -1,13 +1,13 @@
// First, init config. // First, init config.
import { config, loadConfig } from "@/src/services/configService"; import { config, configPath, loadConfig } from "@/src/services/configService";
import fs from "fs"; import fs from "fs";
try { try {
loadConfig(); loadConfig();
} catch (e) { } catch (e) {
if (fs.existsSync("config.json")) { if (fs.existsSync("config.json")) {
console.log("Failed to load config.json: " + (e as Error).message); console.log("Failed to load " + configPath + ": " + (e as Error).message);
} else { } else {
console.log("Failed to load config.json. You can copy config.json.example to create your config.json."); console.log("Failed to load " + configPath + ". You can copy config.json.example to create your config file.");
} }
process.exit(1); process.exit(1);
} }
@ -22,6 +22,7 @@ import { JSONStringify } from "json-with-bigint";
import { startWebServer } from "./services/webService"; import { startWebServer } from "./services/webService";
import { validateConfig } from "@/src/services/configWatcherService"; import { validateConfig } from "@/src/services/configWatcherService";
import { updateWorldStateCollections } from "./services/worldStateService";
// Patch JSON.stringify to work flawlessly with Bigints. // Patch JSON.stringify to work flawlessly with Bigints.
JSON.stringify = JSONStringify; JSON.stringify = JSONStringify;
@ -33,6 +34,11 @@ mongoose
.then(() => { .then(() => {
logger.info("Connected to MongoDB"); logger.info("Connected to MongoDB");
startWebServer(); startWebServer();
void updateWorldStateCollections();
setInterval(() => {
void updateWorldStateCollections();
}, 60_000);
}) })
.catch(error => { .catch(error => {
if (error instanceof Error) { if (error instanceof Error) {

View File

@ -251,12 +251,6 @@ const ArchonCrystalUpgradeSchema = new Schema<IArchonCrystalUpgrade>(
{ _id: false } { _id: false }
); );
ArchonCrystalUpgradeSchema.set("toJSON", {
transform(_document, returnedObject) {
delete returnedObject.__v;
}
});
const boosterSchema = new Schema<IBooster>( const boosterSchema = new Schema<IBooster>(
{ {
ExpiryDate: Number, ExpiryDate: Number,
@ -1079,6 +1073,11 @@ EquipmentSchema.set("toJSON", {
if (db.UmbraDate) { if (db.UmbraDate) {
client.UmbraDate = toMongoDate(db.UmbraDate); client.UmbraDate = toMongoDate(db.UmbraDate);
} }
if (client.ArchonCrystalUpgrades) {
// For some reason, mongoose turns empty objects here into nulls, so we have to fix it.
client.ArchonCrystalUpgrades = client.ArchonCrystalUpgrades.map(x => (x as unknown) ?? {});
}
} }
}); });
@ -1704,7 +1703,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
LastInventorySync: Schema.Types.ObjectId, LastInventorySync: Schema.Types.ObjectId,
Mailbox: MailboxSchema, Mailbox: MailboxSchema,
HandlerPoints: Number, HandlerPoints: Number,
ChallengesFixVersion: { type: Number, default: 6 }, ChallengesFixVersion: Number,
PlayedParkourTutorial: Boolean, PlayedParkourTutorial: Boolean,
//ActiveLandscapeTraps: [Schema.Types.Mixed], //ActiveLandscapeTraps: [Schema.Types.Mixed],
//RepVotes: [Schema.Types.Mixed], //RepVotes: [Schema.Types.Mixed],

View File

@ -11,13 +11,13 @@ const databaseAccountSchema = new Schema<IDatabaseAccountJson>(
email: { type: String, required: true, unique: true }, email: { type: String, required: true, unique: true },
password: { type: String, required: true }, password: { type: String, required: true },
DisplayName: { type: String, required: true, unique: true }, DisplayName: { type: String, required: true, unique: true },
CountryCode: { type: String, required: true }, CountryCode: { type: String, default: "" },
ClientType: { type: String }, ClientType: { type: String },
CrossPlatformAllowed: { type: Boolean, required: true }, CrossPlatformAllowed: { type: Boolean, default: true },
ForceLogoutVersion: { type: Number, required: true }, ForceLogoutVersion: { type: Number, default: 0 },
AmazonAuthToken: { type: String }, AmazonAuthToken: { type: String },
AmazonRefreshToken: { type: String }, AmazonRefreshToken: { type: String },
ConsentNeeded: { type: Boolean, required: true }, ConsentNeeded: { type: Boolean, default: false },
TrackedSettings: { type: [String], default: [] }, TrackedSettings: { type: [String], default: [] },
Nonce: { type: Number, default: 0 }, Nonce: { type: Number, default: 0 },
BuildLabel: String, BuildLabel: String,

View File

@ -0,0 +1,14 @@
import { IFissureDatabase } from "@/src/types/worldStateTypes";
import { model, Schema } from "mongoose";
const fissureSchema = new Schema<IFissureDatabase>({
Activation: Date,
Expiry: Date,
Node: String, // must be unique
Modifier: String,
Hard: Boolean
});
fissureSchema.index({ Expiry: 1 }, { expireAfterSeconds: 0 }); // With this, MongoDB will automatically delete expired entries.
export const Fissure = model<IFissureDatabase>("Fissure", fissureSchema);

View File

@ -33,6 +33,7 @@ import { createAllianceController } from "@/src/controllers/api/createAllianceCo
import { createGuildController } from "@/src/controllers/api/createGuildController"; import { createGuildController } from "@/src/controllers/api/createGuildController";
import { creditsController } from "@/src/controllers/api/creditsController"; import { creditsController } from "@/src/controllers/api/creditsController";
import { crewMembersController } from "@/src/controllers/api/crewMembersController"; import { crewMembersController } from "@/src/controllers/api/crewMembersController";
import { crewShipFusionController } from "@/src/controllers/api/crewShipFusionController";
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController"; import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController"; import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController"; import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
@ -132,6 +133,7 @@ import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDeco
import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController"; import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController"; import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController";
import { setShipVignetteController } from "@/src/controllers/api/setShipVignetteController"; import { setShipVignetteController } from "@/src/controllers/api/setShipVignetteController";
import { setSuitInfectionController } from "@/src/controllers/api/setSuitInfectionController";
import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController"; import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController"; import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController";
import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController"; import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController";
@ -147,6 +149,7 @@ import { syndicateStandingBonusController } from "@/src/controllers/api/syndicat
import { tauntHistoryController } from "@/src/controllers/api/tauntHistoryController"; import { tauntHistoryController } from "@/src/controllers/api/tauntHistoryController";
import { tradingController } from "@/src/controllers/api/tradingController"; import { tradingController } from "@/src/controllers/api/tradingController";
import { trainingResultController } from "@/src/controllers/api/trainingResultController"; import { trainingResultController } from "@/src/controllers/api/trainingResultController";
import { umbraController } from "@/src/controllers/api/umbraController";
import { unlockShipFeatureController } from "@/src/controllers/api/unlockShipFeatureController"; import { unlockShipFeatureController } from "@/src/controllers/api/unlockShipFeatureController";
import { updateAlignmentController } from "@/src/controllers/api/updateAlignmentController"; import { updateAlignmentController } from "@/src/controllers/api/updateAlignmentController";
import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController"; import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController";
@ -245,6 +248,7 @@ apiRouter.post("/contributeToVault.php", contributeToVaultController);
apiRouter.post("/createAlliance.php", createAllianceController); apiRouter.post("/createAlliance.php", createAllianceController);
apiRouter.post("/createGuild.php", createGuildController); apiRouter.post("/createGuild.php", createGuildController);
apiRouter.post("/crewMembers.php", crewMembersController); apiRouter.post("/crewMembers.php", crewMembersController);
apiRouter.post("/crewShipFusion.php", crewShipFusionController);
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController); apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController); apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController); apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
@ -280,6 +284,7 @@ apiRouter.post("/inventorySlots.php", inventorySlotsController);
apiRouter.post("/joinSession.php", joinSessionController); apiRouter.post("/joinSession.php", joinSessionController);
apiRouter.post("/login.php", loginController); apiRouter.post("/login.php", loginController);
apiRouter.post("/loginRewardsSelection.php", loginRewardsSelectionController); apiRouter.post("/loginRewardsSelection.php", loginRewardsSelectionController);
apiRouter.post("/logout.php", logoutController); // from ~U16, don't know when they changed it to GET
apiRouter.post("/maturePet.php", maturePetController); apiRouter.post("/maturePet.php", maturePetController);
apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController); apiRouter.post("/missionInventoryUpdate.php", missionInventoryUpdateController);
apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController); apiRouter.post("/modularWeaponCrafting.php", modularWeaponCraftingController);
@ -317,6 +322,7 @@ apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController); apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController); apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController);
apiRouter.post("/setShipVignette.php", setShipVignetteController); apiRouter.post("/setShipVignette.php", setShipVignetteController);
apiRouter.post("/setSuitInfection.php", setSuitInfectionController);
apiRouter.post("/setWeaponSkillTree.php", setWeaponSkillTreeController); apiRouter.post("/setWeaponSkillTree.php", setWeaponSkillTreeController);
apiRouter.post("/shipDecorations.php", shipDecorationsController); apiRouter.post("/shipDecorations.php", shipDecorationsController);
apiRouter.post("/startCollectibleEntry.php", startCollectibleEntryController); apiRouter.post("/startCollectibleEntry.php", startCollectibleEntryController);
@ -327,6 +333,7 @@ apiRouter.post("/syndicateSacrifice.php", syndicateSacrificeController);
apiRouter.post("/syndicateStandingBonus.php", syndicateStandingBonusController); apiRouter.post("/syndicateStandingBonus.php", syndicateStandingBonusController);
apiRouter.post("/tauntHistory.php", tauntHistoryController); apiRouter.post("/tauntHistory.php", tauntHistoryController);
apiRouter.post("/trainingResult.php", trainingResultController); apiRouter.post("/trainingResult.php", trainingResultController);
apiRouter.post("/umbra.php", umbraController);
apiRouter.post("/unlockShipFeature.php", unlockShipFeatureController); apiRouter.post("/unlockShipFeature.php", unlockShipFeatureController);
apiRouter.post("/updateAlignment.php", updateAlignmentController); apiRouter.post("/updateAlignment.php", updateAlignmentController);
apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController); apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController);

View File

@ -11,6 +11,7 @@ import { renameAccountController } from "@/src/controllers/custom/renameAccountC
import { ircDroppedController } from "@/src/controllers/custom/ircDroppedController"; import { ircDroppedController } from "@/src/controllers/custom/ircDroppedController";
import { unlockAllIntrinsicsController } from "@/src/controllers/custom/unlockAllIntrinsicsController"; import { unlockAllIntrinsicsController } from "@/src/controllers/custom/unlockAllIntrinsicsController";
import { addMissingMaxRankModsController } from "@/src/controllers/custom/addMissingMaxRankModsController"; import { addMissingMaxRankModsController } from "@/src/controllers/custom/addMissingMaxRankModsController";
import { webuiFileChangeDetectedController } from "@/src/controllers/custom/webuiFileChangeDetectedController";
import { createAccountController } from "@/src/controllers/custom/createAccountController"; import { createAccountController } from "@/src/controllers/custom/createAccountController";
import { createMessageController } from "@/src/controllers/custom/createMessageController"; import { createMessageController } from "@/src/controllers/custom/createMessageController";
@ -20,10 +21,10 @@ import { addXpController } from "@/src/controllers/custom/addXpController";
import { importController } from "@/src/controllers/custom/importController"; import { importController } from "@/src/controllers/custom/importController";
import { manageQuestsController } from "@/src/controllers/custom/manageQuestsController"; import { manageQuestsController } from "@/src/controllers/custom/manageQuestsController";
import { setEvolutionProgressController } from "@/src/controllers/custom/setEvolutionProgressController"; import { setEvolutionProgressController } from "@/src/controllers/custom/setEvolutionProgressController";
import { setBoosterController } from "@/src/controllers/custom/setBoosterController";
import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController"; import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController"; import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
import { setBoosterController } from "../controllers/custom/setBoosterController";
const customRouter = express.Router(); const customRouter = express.Router();
@ -38,6 +39,7 @@ customRouter.get("/renameAccount", renameAccountController);
customRouter.get("/ircDropped", ircDroppedController); customRouter.get("/ircDropped", ircDroppedController);
customRouter.get("/unlockAllIntrinsics", unlockAllIntrinsicsController); customRouter.get("/unlockAllIntrinsics", unlockAllIntrinsicsController);
customRouter.get("/addMissingMaxRankMods", addMissingMaxRankModsController); customRouter.get("/addMissingMaxRankMods", addMissingMaxRankModsController);
customRouter.get("/webuiFileChangeDetected", webuiFileChangeDetectedController);
customRouter.post("/createAccount", createAccountController); customRouter.post("/createAccount", createAccountController);
customRouter.post("/createMessage", createMessageController); customRouter.post("/createMessage", createMessageController);

View File

@ -1,6 +1,9 @@
import express from "express"; import express from "express";
import path from "path"; import path from "path";
import { repoDir, rootDir } from "@/src/helpers/pathHelper"; import { repoDir, rootDir } from "@/src/helpers/pathHelper";
import { args } from "@/src/helpers/commandLineArguments";
const baseDir = args.dev ? repoDir : rootDir;
const webuiRouter = express.Router(); const webuiRouter = express.Router();
@ -19,29 +22,29 @@ webuiRouter.use("/webui", (req, res, next) => {
// Serve virtual routes // Serve virtual routes
webuiRouter.get("/webui/inventory", (_req, res) => { webuiRouter.get("/webui/inventory", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html")); res.sendFile(path.join(baseDir, "static/webui/index.html"));
}); });
webuiRouter.get(/webui\/powersuit\/(.+)/, (_req, res) => { webuiRouter.get(/webui\/powersuit\/(.+)/, (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html")); res.sendFile(path.join(baseDir, "static/webui/index.html"));
}); });
webuiRouter.get("/webui/mods", (_req, res) => { webuiRouter.get("/webui/mods", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html")); res.sendFile(path.join(baseDir, "static/webui/index.html"));
}); });
webuiRouter.get("/webui/settings", (_req, res) => { webuiRouter.get("/webui/settings", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html")); res.sendFile(path.join(baseDir, "static/webui/index.html"));
}); });
webuiRouter.get("/webui/quests", (_req, res) => { webuiRouter.get("/webui/quests", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html")); res.sendFile(path.join(baseDir, "static/webui/index.html"));
}); });
webuiRouter.get("/webui/cheats", (_req, res) => { webuiRouter.get("/webui/cheats", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html")); res.sendFile(path.join(baseDir, "static/webui/index.html"));
}); });
webuiRouter.get("/webui/import", (_req, res) => { webuiRouter.get("/webui/import", (_req, res) => {
res.sendFile(path.join(rootDir, "static/webui/index.html")); res.sendFile(path.join(baseDir, "static/webui/index.html"));
}); });
// Serve static files // Serve static files
webuiRouter.use("/webui", express.static(path.join(rootDir, "static/webui"))); webuiRouter.use("/webui", express.static(path.join(baseDir, "static/webui")));
// Serve favicon // Serve favicon
webuiRouter.get("/favicon.ico", (_req, res) => { webuiRouter.get("/favicon.ico", (_req, res) => {
@ -58,7 +61,7 @@ webuiRouter.get("/webui/riven-tool/RivenParser.js", (_req, res) => {
// Serve translations // Serve translations
webuiRouter.get("/translations/:file", (req, res) => { webuiRouter.get("/translations/:file", (req, res) => {
res.sendFile(path.join(rootDir, `static/webui/translations/${req.params.file}`)); res.sendFile(path.join(baseDir, `static/webui/translations/${req.params.file}`));
}); });
export { webuiRouter }; export { webuiRouter };

View File

@ -1,8 +1,9 @@
import fs from "fs"; import fs from "fs";
import path from "path"; import path from "path";
import { repoDir } from "@/src/helpers/pathHelper"; import { repoDir } from "@/src/helpers/pathHelper";
import { args } from "@/src/helpers/commandLineArguments";
interface IConfig { export interface IConfig {
mongodbUrl: string; mongodbUrl: string;
logger: { logger: {
files: boolean; files: boolean;
@ -25,6 +26,10 @@ interface IConfig {
infiniteRegalAya?: boolean; infiniteRegalAya?: boolean;
infiniteHelminthMaterials?: boolean; infiniteHelminthMaterials?: boolean;
claimingBlueprintRefundsIngredients?: boolean; claimingBlueprintRefundsIngredients?: boolean;
dontSubtractPurchaseCreditCost?: boolean;
dontSubtractPurchasePlatinumCost?: boolean;
dontSubtractPurchaseItemCost?: boolean;
dontSubtractPurchaseStandingCost?: boolean;
dontSubtractVoidTraces?: boolean; dontSubtractVoidTraces?: boolean;
dontSubtractConsumables?: boolean; dontSubtractConsumables?: boolean;
unlockAllShipFeatures?: boolean; unlockAllShipFeatures?: boolean;
@ -45,6 +50,7 @@ interface IConfig {
noDeathMarks?: boolean; noDeathMarks?: boolean;
noKimCooldowns?: boolean; noKimCooldowns?: boolean;
syndicateMissionsRepeatable?: boolean; syndicateMissionsRepeatable?: boolean;
unlockAllProfitTakerStages?: boolean;
instantFinishRivenChallenge?: boolean; instantFinishRivenChallenge?: boolean;
instantResourceExtractorDrones?: boolean; instantResourceExtractorDrones?: boolean;
noResourceExtractorDronesDamage?: boolean; noResourceExtractorDronesDamage?: boolean;
@ -55,6 +61,7 @@ interface IConfig {
noDojoResearchCosts?: boolean; noDojoResearchCosts?: boolean;
noDojoResearchTime?: boolean; noDojoResearchTime?: boolean;
fastClanAscension?: boolean; fastClanAscension?: boolean;
missionsCanGiveAllRelics?: boolean;
spoofMasteryRank?: number; spoofMasteryRank?: number;
nightwaveStandingMultiplier?: number; nightwaveStandingMultiplier?: number;
worldState?: { worldState?: {
@ -64,14 +71,16 @@ interface IConfig {
starDays?: boolean; starDays?: boolean;
eidolonOverride?: string; eidolonOverride?: string;
vallisOverride?: string; vallisOverride?: string;
duviriOverride?: string;
nightwaveOverride?: string; nightwaveOverride?: string;
circuitGameModes?: string[];
}; };
dev?: { dev?: {
keepVendorsExpired?: boolean; keepVendorsExpired?: boolean;
}; };
} }
export const configPath = path.join(repoDir, "config.json"); export const configPath = path.join(repoDir, args.configPath ?? "config.json");
export const config: IConfig = { export const config: IConfig = {
mongodbUrl: "mongodb://127.0.0.1:27017/openWF", mongodbUrl: "mongodb://127.0.0.1:27017/openWF",

View File

@ -2,14 +2,14 @@ import fs from "fs";
import fsPromises from "fs/promises"; import fsPromises from "fs/promises";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { config, configPath, loadConfig } from "./configService"; import { config, configPath, loadConfig } from "./configService";
import { getWebPorts, startWebServer, stopWebServer } from "./webService"; import { getWebPorts, sendWsBroadcast, startWebServer, stopWebServer } from "./webService";
let amnesia = false; let amnesia = false;
fs.watchFile(configPath, () => { fs.watchFile(configPath, () => {
if (amnesia) { if (amnesia) {
amnesia = false; amnesia = false;
} else { } else {
logger.info("Detected a change to config.json, reloading its contents."); logger.info("Detected a change to config file, reloading its contents.");
try { try {
loadConfig(); loadConfig();
} catch (e) { } catch (e) {
@ -21,7 +21,13 @@ fs.watchFile(configPath, () => {
const webPorts = getWebPorts(); const webPorts = getWebPorts();
if (config.httpPort != webPorts.http || config.httpsPort != webPorts.https) { if (config.httpPort != webPorts.http || config.httpsPort != webPorts.https) {
logger.info(`Restarting web server to apply port changes.`); logger.info(`Restarting web server to apply port changes.`);
// Tell webui clients to reload with new port
sendWsBroadcast({ ports: { http: config.httpPort, https: config.httpsPort } });
void stopWebServer().then(startWebServer); void stopWebServer().then(startWebServer);
} else {
sendWsBroadcast({ config_reloaded: true });
} }
} }
}); });
@ -41,17 +47,11 @@ export const validateConfig = (): void => {
} }
} }
if (modified) { if (modified) {
logger.info(`Updating config.json to fix some issues with it.`); logger.info(`Updating config file to fix some issues with it.`);
void saveConfig(); void saveConfig();
} }
}; };
export const updateConfig = async (data: string): Promise<void> => {
amnesia = true;
await fsPromises.writeFile(configPath, data);
Object.assign(config, JSON.parse(data));
};
export const saveConfig = async (): Promise<void> => { export const saveConfig = async (): Promise<void> => {
amnesia = true; amnesia = true;
await fsPromises.writeFile(configPath, JSON.stringify(config, null, 2)); await fsPromises.writeFile(configPath, JSON.stringify(config, null, 2));

View File

@ -50,14 +50,17 @@ export const createNewEventMessages = async (req: Request): Promise<void> => {
await account.save(); await account.save();
}; };
export const createMessage = async (accountId: string | Types.ObjectId, messages: IMessageCreationTemplate[]) => { export const createMessage = async (
accountId: string | Types.ObjectId,
messages: IMessageCreationTemplate[]
): Promise<HydratedDocument<IMessageDatabase>[]> => {
const ownerIdMessages = messages.map(m => ({ const ownerIdMessages = messages.map(m => ({
...m, ...m,
ownerId: accountId ownerId: accountId
})); }));
const savedMessages = await Inbox.insertMany(ownerIdMessages); const savedMessages = await Inbox.insertMany(ownerIdMessages);
return savedMessages; return savedMessages as HydratedDocument<IMessageDatabase>[];
}; };
export interface IMessageCreationTemplate extends Omit<IMessageDatabase, "_id" | "date" | "ownerId"> { export interface IMessageCreationTemplate extends Omit<IMessageDatabase, "_id" | "date" | "ownerId"> {

View File

@ -1580,7 +1580,7 @@ export const addMiscItem = (
inventory: TInventoryDatabaseDocument, inventory: TInventoryDatabaseDocument,
type: string, type: string,
count: number, count: number,
inventoryChanges: IInventoryChanges inventoryChanges: IInventoryChanges = {}
): void => { ): void => {
const miscItemChanges: IMiscItem[] = [ const miscItemChanges: IMiscItem[] = [
{ {
@ -1731,12 +1731,27 @@ export const addFocusXpIncreases = (inventory: TInventoryDatabaseDocument, focus
AP_ANY AP_ANY
} }
inventory.FocusXP ??= { AP_ATTACK: 0, AP_DEFENSE: 0, AP_TACTIC: 0, AP_POWER: 0, AP_WARD: 0 }; inventory.FocusXP ??= {};
inventory.FocusXP.AP_ATTACK += focusXpPlus[FocusType.AP_ATTACK]; if (focusXpPlus[FocusType.AP_ATTACK]) {
inventory.FocusXP.AP_DEFENSE += focusXpPlus[FocusType.AP_DEFENSE]; inventory.FocusXP.AP_ATTACK ??= 0;
inventory.FocusXP.AP_TACTIC += focusXpPlus[FocusType.AP_TACTIC]; inventory.FocusXP.AP_ATTACK += focusXpPlus[FocusType.AP_ATTACK];
inventory.FocusXP.AP_POWER += focusXpPlus[FocusType.AP_POWER]; }
inventory.FocusXP.AP_WARD += focusXpPlus[FocusType.AP_WARD]; if (focusXpPlus[FocusType.AP_DEFENSE]) {
inventory.FocusXP.AP_DEFENSE ??= 0;
inventory.FocusXP.AP_DEFENSE += focusXpPlus[FocusType.AP_DEFENSE];
}
if (focusXpPlus[FocusType.AP_TACTIC]) {
inventory.FocusXP.AP_TACTIC ??= 0;
inventory.FocusXP.AP_TACTIC += focusXpPlus[FocusType.AP_TACTIC];
}
if (focusXpPlus[FocusType.AP_POWER]) {
inventory.FocusXP.AP_POWER ??= 0;
inventory.FocusXP.AP_POWER += focusXpPlus[FocusType.AP_POWER];
}
if (focusXpPlus[FocusType.AP_WARD]) {
inventory.FocusXP.AP_WARD ??= 0;
inventory.FocusXP.AP_WARD += focusXpPlus[FocusType.AP_WARD];
}
if (!config.noDailyFocusLimit) { if (!config.noDailyFocusLimit) {
inventory.DailyFocus -= focusXpPlus.reduce((a, b) => a + b, 0); inventory.DailyFocus -= focusXpPlus.reduce((a, b) => a + b, 0);
@ -1810,12 +1825,15 @@ export const addChallenges = (
return affiliationMods; return affiliationMods;
}; };
export const addMissionComplete = (inventory: TInventoryDatabaseDocument, { Tag, Completes }: IMission): void => { export const addMissionComplete = (inventory: TInventoryDatabaseDocument, { Tag, Completes, Tier }: IMission): void => {
const { Missions } = inventory; const { Missions } = inventory;
const itemIndex = Missions.findIndex(item => item.Tag === Tag); const itemIndex = Missions.findIndex(item => item.Tag === Tag);
if (itemIndex !== -1) { if (itemIndex !== -1) {
Missions[itemIndex].Completes += Completes; Missions[itemIndex].Completes += Completes;
if (Tier) {
Missions[itemIndex].Tier = Tier;
}
} else { } else {
Missions.push({ Tag, Completes }); Missions.push({ Tag, Completes });
} }

View File

@ -18,6 +18,23 @@ export const isNameTaken = async (name: string): Promise<boolean> => {
return !!(await Account.findOne({ DisplayName: name })); return !!(await Account.findOne({ DisplayName: name }));
}; };
export const createNonce = (): number => {
return Math.round(Math.random() * Number.MAX_SAFE_INTEGER);
};
export const getUsernameFromEmail = async (email: string): Promise<string> => {
const nameFromEmail = email.substring(0, email.indexOf("@"));
let name = nameFromEmail || email.substring(1) || "SpaceNinja";
if (await isNameTaken(name)) {
let suffix = 0;
do {
++suffix;
name = nameFromEmail + suffix;
} while (await isNameTaken(name));
}
return nameFromEmail;
};
export const createAccount = async (accountData: IDatabaseAccountRequiredFields): Promise<IDatabaseAccountJson> => { export const createAccount = async (accountData: IDatabaseAccountRequiredFields): Promise<IDatabaseAccountJson> => {
const account = new Account(accountData); const account = new Account(accountData);
try { try {

View File

@ -2,6 +2,7 @@ import {
ExportEnemies, ExportEnemies,
ExportFusionBundles, ExportFusionBundles,
ExportRegions, ExportRegions,
ExportRelics,
ExportRewards, ExportRewards,
IMissionReward as IMissionRewardExternal, IMissionReward as IMissionRewardExternal,
IRegion, IRegion,
@ -1204,8 +1205,10 @@ export const addMissionRewards = async (
if (syndicateEntry && syndicateEntry.Jobs) { if (syndicateEntry && syndicateEntry.Jobs) {
let currentJob = syndicateEntry.Jobs[rewardInfo.JobTier!]; let currentJob = syndicateEntry.Jobs[rewardInfo.JobTier!];
if (syndicateEntry.Tag === "EntratiSyndicate") { if (syndicateEntry.Tag === "EntratiSyndicate") {
const vault = syndicateEntry.Jobs.find(j => j.locationTag === locationTag); if (jobType.endsWith("VaultBounty")) {
if (vault) currentJob = vault; const vault = syndicateEntry.Jobs.find(j => j.locationTag === locationTag);
if (vault) currentJob = vault;
}
let medallionAmount = Math.floor(currentJob.xpAmounts[rewardInfo.JobStage] / (rewardInfo.Q ? 0.8 : 1)); let medallionAmount = Math.floor(currentJob.xpAmounts[rewardInfo.JobStage] / (rewardInfo.Q ? 0.8 : 1));
if ( if (
@ -1552,8 +1555,10 @@ function getRandomMissionDrops(
let job = syndicateEntry.Jobs[RewardInfo.JobTier!]; let job = syndicateEntry.Jobs[RewardInfo.JobTier!];
if (syndicateEntry.Tag === "EntratiSyndicate") { if (syndicateEntry.Tag === "EntratiSyndicate") {
const vault = syndicateEntry.Jobs.find(j => j.locationTag === locationTag); if (jobType.endsWith("VaultBounty")) {
if (vault && locationTag) job = vault; const vault = syndicateEntry.Jobs.find(j => j.locationTag === locationTag);
if (vault) job = vault;
}
// if ( // if (
// [ // [
// "DeimosRuinsExterminateBounty", // "DeimosRuinsExterminateBounty",
@ -1801,6 +1806,23 @@ function getRandomMissionDrops(
drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount }); drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
} }
} }
if (config.missionsCanGiveAllRelics) {
for (const drop of drops) {
const itemType = fromStoreItem(drop.StoreItem);
if (itemType in ExportRelics) {
const relic = ExportRelics[itemType];
const replacement = getRandomElement(
Object.entries(ExportRelics).filter(
arr => arr[1].era == relic.era && arr[1].quality == relic.quality
)
)!;
logger.debug(`replacing ${relic.era} ${relic.category} with ${replacement[1].category}`);
drop.StoreItem = toStoreItem(replacement[0]);
}
}
}
return drops; return drops;
} }

View File

@ -67,25 +67,31 @@ export const handlePurchase = async (
if (!offer) { if (!offer) {
throw new Error(`unknown vendor offer: ${ItemId ? ItemId : purchaseRequest.PurchaseParams.StoreItem}`); throw new Error(`unknown vendor offer: ${ItemId ? ItemId : purchaseRequest.PurchaseParams.StoreItem}`);
} }
if (offer.RegularPrice) { if (!config.dontSubtractPurchaseCreditCost) {
combineInventoryChanges( if (offer.RegularPrice) {
prePurchaseInventoryChanges, combineInventoryChanges(
updateCurrency(inventory, offer.RegularPrice[0], false) prePurchaseInventoryChanges,
); updateCurrency(inventory, offer.RegularPrice[0], false)
);
}
} }
if (offer.PremiumPrice) { if (!config.dontSubtractPurchasePlatinumCost) {
combineInventoryChanges( if (offer.PremiumPrice) {
prePurchaseInventoryChanges, combineInventoryChanges(
updateCurrency(inventory, offer.PremiumPrice[0], true) prePurchaseInventoryChanges,
); updateCurrency(inventory, offer.PremiumPrice[0], true)
);
}
} }
if (offer.ItemPrices) { if (!config.dontSubtractPurchaseItemCost) {
handleItemPrices( if (offer.ItemPrices) {
inventory, handleItemPrices(
offer.ItemPrices, inventory,
purchaseRequest.PurchaseParams.Quantity, offer.ItemPrices,
prePurchaseInventoryChanges purchaseRequest.PurchaseParams.Quantity,
); prePurchaseInventoryChanges
);
}
} }
if (offer.LocTagRandSeed !== undefined) { if (offer.LocTagRandSeed !== undefined) {
seed = BigInt(offer.LocTagRandSeed); seed = BigInt(offer.LocTagRandSeed);
@ -179,21 +185,25 @@ export const handlePurchase = async (
x => x.ItemType == purchaseRequest.PurchaseParams.StoreItem x => x.ItemType == purchaseRequest.PurchaseParams.StoreItem
); );
if (offer) { if (offer) {
combineInventoryChanges( if (!config.dontSubtractPurchaseCreditCost) {
purchaseResponse.InventoryChanges, combineInventoryChanges(
updateCurrency(inventory, offer.RegularPrice, false) purchaseResponse.InventoryChanges,
); updateCurrency(inventory, offer.RegularPrice, false)
);
}
if (purchaseRequest.PurchaseParams.ExpectedPrice) { if (purchaseRequest.PurchaseParams.ExpectedPrice) {
throw new Error(`vendor purchase should not have an expected price`); throw new Error(`vendor purchase should not have an expected price`);
} }
const invItem: IMiscItem = { if (!config.dontSubtractPurchaseItemCost) {
ItemType: "/Lotus/Types/Items/MiscItems/PrimeBucks", const invItem: IMiscItem = {
ItemCount: offer.PrimePrice * purchaseRequest.PurchaseParams.Quantity * -1 ItemType: "/Lotus/Types/Items/MiscItems/PrimeBucks",
}; ItemCount: offer.PrimePrice * purchaseRequest.PurchaseParams.Quantity * -1
addMiscItems(inventory, [invItem]); };
purchaseResponse.InventoryChanges.MiscItems ??= []; addMiscItems(inventory, [invItem]);
purchaseResponse.InventoryChanges.MiscItems.push(invItem); purchaseResponse.InventoryChanges.MiscItems ??= [];
purchaseResponse.InventoryChanges.MiscItems.push(invItem);
}
} }
break; break;
} }
@ -211,7 +221,7 @@ export const handlePurchase = async (
Title: lastTitle Title: lastTitle
} }
]; ];
} else { } else if (!config.dontSubtractPurchaseStandingCost) {
const syndicate = ExportSyndicates[syndicateTag]; const syndicate = ExportSyndicates[syndicateTag];
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
if (syndicate) { if (syndicate) {
@ -239,19 +249,19 @@ export const handlePurchase = async (
const vendor = ExportVendors[purchaseRequest.PurchaseParams.SourceId!]; const vendor = ExportVendors[purchaseRequest.PurchaseParams.SourceId!];
const offer = vendor.items.find(x => x.storeItem == purchaseRequest.PurchaseParams.StoreItem); const offer = vendor.items.find(x => x.storeItem == purchaseRequest.PurchaseParams.StoreItem);
if (offer) { if (offer) {
if (typeof offer.credits == "number") { if (typeof offer.credits == "number" && !config.dontSubtractPurchaseCreditCost) {
combineInventoryChanges( combineInventoryChanges(
purchaseResponse.InventoryChanges, purchaseResponse.InventoryChanges,
updateCurrency(inventory, offer.credits, false) updateCurrency(inventory, offer.credits, false)
); );
} }
if (typeof offer.platinum == "number") { if (typeof offer.platinum == "number" && !config.dontSubtractPurchasePlatinumCost) {
combineInventoryChanges( combineInventoryChanges(
purchaseResponse.InventoryChanges, purchaseResponse.InventoryChanges,
updateCurrency(inventory, offer.platinum, true) updateCurrency(inventory, offer.platinum, true)
); );
} }
if (offer.itemPrices) { if (offer.itemPrices && !config.dontSubtractPurchaseItemCost) {
handleItemPrices( handleItemPrices(
inventory, inventory,
offer.itemPrices, offer.itemPrices,
@ -278,15 +288,17 @@ export const handlePurchase = async (
); );
if (offer) { if (offer) {
if (offer.RegularPrice) { if (offer.RegularPrice) {
const invItem: IMiscItem = { if (!config.dontSubtractPurchaseItemCost) {
ItemType: "/Lotus/Types/Items/MiscItems/SchismKey", const invItem: IMiscItem = {
ItemCount: offer.RegularPrice * purchaseRequest.PurchaseParams.Quantity * -1 ItemType: "/Lotus/Types/Items/MiscItems/SchismKey",
}; ItemCount: offer.RegularPrice * purchaseRequest.PurchaseParams.Quantity * -1
};
addMiscItems(inventory, [invItem]); addMiscItems(inventory, [invItem]);
purchaseResponse.InventoryChanges.MiscItems ??= []; purchaseResponse.InventoryChanges.MiscItems ??= [];
purchaseResponse.InventoryChanges.MiscItems.push(invItem); purchaseResponse.InventoryChanges.MiscItems.push(invItem);
}
} else if (!config.infiniteRegalAya) { } else if (!config.infiniteRegalAya) {
inventory.PrimeTokens -= offer.PrimePrice! * purchaseRequest.PurchaseParams.Quantity; inventory.PrimeTokens -= offer.PrimePrice! * purchaseRequest.PurchaseParams.Quantity;

View File

@ -1,57 +1,12 @@
import { unixTimesInMs } from "@/src/constants/timeConstants"; import { unixTimesInMs } from "@/src/constants/timeConstants";
import { isDev } from "@/src/helpers/pathHelper"; import { args } from "@/src/helpers/commandLineArguments";
import { catBreadHash } from "@/src/helpers/stringHelpers"; import { catBreadHash } from "@/src/helpers/stringHelpers";
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
import { mixSeeds, SRng } from "@/src/services/rngService"; import { mixSeeds, SRng } from "@/src/services/rngService";
import { IMongoDate } from "@/src/types/commonTypes";
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes"; import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
import { logger } from "@/src/utils/logger"; import { logger } from "@/src/utils/logger";
import { ExportVendors, IRange, IVendor, IVendorOffer } from "warframe-public-export-plus"; import { ExportVendors, IRange, IVendor, IVendorOffer } from "warframe-public-export-plus";
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
import DeimosHivemindCommisionsManifestFishmonger from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestFishmonger.json";
import DeimosHivemindCommisionsManifestPetVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestPetVendor.json";
import DeimosHivemindCommisionsManifestProspector from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestProspector.json";
import DeimosHivemindCommisionsManifestTokenVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestTokenVendor.json";
import DeimosHivemindCommisionsManifestWeaponsmith from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestWeaponsmith.json";
import DeimosHivemindTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosHivemindTokenVendorManifest.json";
import DeimosPetVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosPetVendorManifest.json";
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
import Temple1999VendorManifest from "@/static/fixed_responses/getVendorInfo/Temple1999VendorManifest.json";
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
const rawVendorManifests: IVendorManifest[] = [
ArchimedeanVendorManifest,
DeimosEntratiFragmentVendorProductsManifest,
DeimosHivemindCommisionsManifestFishmonger,
DeimosHivemindCommisionsManifestPetVendor,
DeimosHivemindCommisionsManifestProspector,
DeimosHivemindCommisionsManifestTokenVendor,
DeimosHivemindCommisionsManifestWeaponsmith,
DeimosHivemindTokenVendorManifest,
DeimosPetVendorManifest,
DuviriAcrithisVendorManifest,
EntratiLabsEntratiLabsCommisionsManifest,
EntratiLabsEntratiLabVendorManifest,
HubsRailjackCrewMemberVendorManifest,
MaskSalesmanManifest,
Nova1999ConquestShopManifest,
OstronPetVendorManifest,
SolarisDebtTokenVendorRepossessionsManifest,
Temple1999VendorManifest,
TeshinHardModeVendorManifest, // uses preprocessing
ZarimanCommisionsManifestArchimedean
];
interface IGeneratableVendorInfo extends Omit<IVendorInfo, "ItemManifest" | "Expiry"> { interface IGeneratableVendorInfo extends Omit<IVendorInfo, "ItemManifest" | "Expiry"> {
cycleOffset?: number; cycleOffset?: number;
cycleDuration: number; cycleDuration: number;
@ -89,23 +44,22 @@ const gcd = (a: number, b: number): number => {
const getCycleDuration = (manifest: IVendor): number => { const getCycleDuration = (manifest: IVendor): number => {
let dur = 0; let dur = 0;
for (const item of manifest.items) { for (const item of manifest.items) {
if (typeof item.durationHours != "number") { if (item.alwaysOffered) {
continue;
}
const durationHours = item.rotatedWeekly ? 168 : item.durationHours;
if (typeof durationHours != "number") {
dur = 1; dur = 1;
break; break;
} }
if (dur != item.durationHours) { if (dur != durationHours) {
dur = gcd(dur, item.durationHours); dur = gcd(dur, durationHours);
} }
} }
return dur * unixTimesInMs.hour; return dur * unixTimesInMs.hour;
}; };
export const getVendorManifestByTypeName = (typeName: string): IVendorManifest | undefined => { export const getVendorManifestByTypeName = (typeName: string): IVendorManifest | undefined => {
for (const vendorManifest of rawVendorManifests) {
if (vendorManifest.VendorInfo.TypeName == typeName) {
return preprocessVendorManifest(vendorManifest);
}
}
for (const vendorInfo of generatableVendors) { for (const vendorInfo of generatableVendors) {
if (vendorInfo.TypeName == typeName) { if (vendorInfo.TypeName == typeName) {
return generateVendorManifest(vendorInfo); return generateVendorManifest(vendorInfo);
@ -124,11 +78,6 @@ export const getVendorManifestByTypeName = (typeName: string): IVendorManifest |
}; };
export const getVendorManifestByOid = (oid: string): IVendorManifest | undefined => { export const getVendorManifestByOid = (oid: string): IVendorManifest | undefined => {
for (const vendorManifest of rawVendorManifests) {
if (vendorManifest.VendorInfo._id.$oid == oid) {
return preprocessVendorManifest(vendorManifest);
}
}
for (const vendorInfo of generatableVendors) { for (const vendorInfo of generatableVendors) {
if (vendorInfo._id.$oid == oid) { if (vendorInfo._id.$oid == oid) {
return generateVendorManifest(vendorInfo); return generateVendorManifest(vendorInfo);
@ -185,30 +134,6 @@ export const applyStandingToVendorManifest = (
}; };
}; };
const preprocessVendorManifest = (originalManifest: IVendorManifest): IVendorManifest => {
if (Date.now() >= parseInt(originalManifest.VendorInfo.Expiry.$date.$numberLong)) {
const manifest = structuredClone(originalManifest);
const info = manifest.VendorInfo;
refreshExpiry(info.Expiry);
for (const offer of info.ItemManifest) {
refreshExpiry(offer.Expiry);
}
return manifest;
}
return originalManifest;
};
const refreshExpiry = (expiry: IMongoDate): void => {
const period = parseInt(expiry.$date.$numberLong);
if (Date.now() >= period) {
const epoch = 1734307200_000; // Monday (for weekly schedules)
const iteration = Math.trunc((Date.now() - epoch) / period);
const start = epoch + iteration * period;
const end = start + period;
expiry.$date.$numberLong = end.toString();
}
};
const toRange = (value: IRange | number): IRange => { const toRange = (value: IRange | number): IRange => {
if (typeof value == "number") { if (typeof value == "number") {
return { minValue: value, maxValue: value }; return { minValue: value, maxValue: value };
@ -232,6 +157,18 @@ const getCycleDurationRange = (manifest: IVendor): IRange | undefined => {
return res.maxValue != 0 ? res : undefined; return res.maxValue != 0 ? res : undefined;
}; };
type TOfferId = string;
const getOfferId = (offer: IVendorOffer | IItemManifest): TOfferId => {
if ("storeItem" in offer) {
// IVendorOffer
return offer.storeItem + "x" + offer.quantity;
} else {
// IItemManifest
return offer.StoreItem + "x" + offer.QuantityMultiplier;
}
};
const vendorManifestCache: Record<string, IVendorManifest> = {}; const vendorManifestCache: Record<string, IVendorManifest> = {};
const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifest => { const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifest => {
@ -272,47 +209,78 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
const rng = new SRng(mixSeeds(vendorSeed, cycleIndex)); const rng = new SRng(mixSeeds(vendorSeed, cycleIndex));
const offersToAdd: IVendorOffer[] = []; const offersToAdd: IVendorOffer[] = [];
if (!manifest.isOneBinPerCycle) { if (!manifest.isOneBinPerCycle) {
const remainingItemCapacity: Record<string, number> = {}; // Compute vendor requirements, subtracting existing offers
const remainingItemCapacity: Record<TOfferId, number> = {};
const missingItemsPerBin: Record<number, number> = {};
let numOffersThatNeedToMatchABin = 0;
if (manifest.numItemsPerBin) {
for (let bin = 0; bin != manifest.numItemsPerBin.length; ++bin) {
missingItemsPerBin[bin] = manifest.numItemsPerBin[bin];
numOffersThatNeedToMatchABin += manifest.numItemsPerBin[bin];
}
}
for (const item of manifest.items) { for (const item of manifest.items) {
remainingItemCapacity[item.storeItem] = 1 + item.duplicates; remainingItemCapacity[getOfferId(item)] = 1 + item.duplicates;
} }
for (const offer of info.ItemManifest) { for (const offer of info.ItemManifest) {
remainingItemCapacity[offer.StoreItem] -= 1; remainingItemCapacity[getOfferId(offer)] -= 1;
const bin = parseInt(offer.Bin.substring(4));
if (missingItemsPerBin[bin]) {
missingItemsPerBin[bin] -= 1;
numOffersThatNeedToMatchABin -= 1;
}
} }
if (manifest.numItems && manifest.items.length != manifest.numItems.minValue) {
const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue); // Add permanent offers
while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) { let numUncountedOffers = 0;
// TODO: Consider per-bin item limits let numCountedOffers = 0;
// TODO: Consider item probability weightings let offset = 0;
const item = rng.randomElement(manifest.items)!; for (const item of manifest.items) {
if (remainingItemCapacity[item.storeItem] != 0) { if (item.alwaysOffered || item.rotatedWeekly) {
remainingItemCapacity[item.storeItem] -= 1; ++numUncountedOffers;
const id = getOfferId(item);
if (remainingItemCapacity[id] != 0) {
remainingItemCapacity[id] -= 1;
offersToAdd.push(item); offersToAdd.push(item);
++offset;
} }
} else {
numCountedOffers += 1 + item.duplicates;
} }
} else { }
for (const item of manifest.items) {
if (!item.alwaysOffered && remainingItemCapacity[item.storeItem] != 0) { // Add counted offers
remainingItemCapacity[item.storeItem] -= 1; const useRng =
offersToAdd.push(item); manifest.numItems &&
(manifest.numItems.minValue != manifest.numItems.maxValue ||
manifest.numItems.minValue != numCountedOffers);
const numItemsTarget = manifest.numItems
? numUncountedOffers +
(useRng
? rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue)
: manifest.numItems.minValue)
: manifest.items.length;
let i = 0;
const rollableOffers = manifest.items.filter(x => x.probability !== undefined) as (Omit<
IVendorOffer,
"probability"
> & { probability: number })[];
while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) {
const item = useRng ? rng.randomReward(rollableOffers)! : rollableOffers[i++];
if (
remainingItemCapacity[getOfferId(item)] != 0 &&
(numOffersThatNeedToMatchABin == 0 || missingItemsPerBin[item.bin])
) {
remainingItemCapacity[getOfferId(item)] -= 1;
if (missingItemsPerBin[item.bin]) {
missingItemsPerBin[item.bin] -= 1;
numOffersThatNeedToMatchABin -= 1;
} }
offersToAdd.splice(offset, 0, item);
} }
for (const e of Object.entries(remainingItemCapacity)) { if (i == rollableOffers.length) {
const item = manifest.items.find(x => x.storeItem == e[0])!; i = 0;
if (!item.alwaysOffered) {
while (e[1] != 0) {
e[1] -= 1;
offersToAdd.push(item);
}
}
} }
for (const item of manifest.items) {
if (item.alwaysOffered && remainingItemCapacity[item.storeItem] != 0) {
remainingItemCapacity[item.storeItem] -= 1;
offersToAdd.push(item);
}
}
offersToAdd.reverse();
} }
} else { } else {
const binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now. const binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
@ -325,16 +293,21 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
const cycleStart = cycleOffset + cycleIndex * cycleDuration; const cycleStart = cycleOffset + cycleIndex * cycleDuration;
for (const rawItem of offersToAdd) { for (const rawItem of offersToAdd) {
const durationHoursRange = toRange(rawItem.durationHours ?? cycleDuration); const durationHoursRange = toRange(rawItem.durationHours ?? cycleDuration);
const expiry = const expiry = rawItem.alwaysOffered
cycleStart + ? 2051240400_000
rng.randomInt(durationHoursRange.minValue, durationHoursRange.maxValue) * unixTimesInMs.hour; : cycleStart +
(rawItem.rotatedWeekly
? unixTimesInMs.week
: rng.randomInt(durationHoursRange.minValue, durationHoursRange.maxValue) * unixTimesInMs.hour);
const item: IItemManifest = { const item: IItemManifest = {
StoreItem: rawItem.storeItem, StoreItem: rawItem.storeItem,
ItemPrices: rawItem.itemPrices?.map(itemPrice => ({ ...itemPrice, ProductCategory: "MiscItems" })), ItemPrices: rawItem.itemPrices?.map(itemPrice => ({ ...itemPrice, ProductCategory: "MiscItems" })),
Bin: "BIN_" + rawItem.bin, Bin: "BIN_" + rawItem.bin,
QuantityMultiplier: rawItem.quantity, QuantityMultiplier: rawItem.quantity,
Expiry: { $date: { $numberLong: expiry.toString() } }, Expiry: { $date: { $numberLong: expiry.toString() } },
AllowMultipurchase: false, PurchaseQuantityLimit: rawItem.purchaseLimit,
RotatedWeekly: rawItem.rotatedWeekly,
AllowMultipurchase: rawItem.purchaseLimit !== 1,
Id: { Id: {
$oid: $oid:
((cycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") + ((cycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") +
@ -343,7 +316,7 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
} }
}; };
if (rawItem.numRandomItemPrices) { if (rawItem.numRandomItemPrices) {
item.ItemPrices = []; item.ItemPrices ??= [];
for (let i = 0; i != rawItem.numRandomItemPrices; ++i) { for (let i = 0; i != rawItem.numRandomItemPrices; ++i) {
let itemPrice: { type: string; count: IRange }; let itemPrice: { type: string; count: IRange };
do { do {
@ -383,6 +356,14 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
info.ItemManifest.push(item); info.ItemManifest.push(item);
} }
if (manifest.numItemsPerBin) {
info.ItemManifest.sort((a, b) => {
const aBin = parseInt(a.Bin.substring(4));
const bBin = parseInt(b.Bin.substring(4));
return aBin == bBin ? 0 : aBin < bBin ? +1 : -1;
});
}
// Update vendor expiry // Update vendor expiry
let soonestOfferExpiry: number = Number.MAX_SAFE_INTEGER; let soonestOfferExpiry: number = Number.MAX_SAFE_INTEGER;
for (const offer of info.ItemManifest) { for (const offer of info.ItemManifest) {
@ -398,7 +379,14 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
return cacheEntry; return cacheEntry;
}; };
if (isDev) { if (args.dev) {
if (
getCycleDuration(ExportVendors["/Lotus/Types/Game/VendorManifests/Hubs/TeshinHardModeVendorManifest"]) !=
unixTimesInMs.week
) {
logger.warn(`getCycleDuration self test failed`);
}
const ads = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest")! const ads = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest")!
.VendorInfo.ItemManifest; .VendorInfo.ItemManifest;
if ( if (
@ -424,4 +412,39 @@ if (isDev) {
) { ) {
logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest`); logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest`);
} }
const cms = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Hubs/RailjackCrewMemberVendorManifest")!
.VendorInfo.ItemManifest;
if (
cms.length != 9 ||
cms[0].Bin != "BIN_2" ||
cms[8].Bin != "BIN_0" ||
cms.reduce((a, x) => a + (x.Bin == "BIN_2" ? 1 : 0), 0) < 2 ||
cms.reduce((a, x) => a + (x.Bin == "BIN_1" ? 1 : 0), 0) < 2 ||
cms.reduce((a, x) => a + (x.Bin == "BIN_0" ? 1 : 0), 0) < 4
) {
logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/RailjackCrewMemberVendorManifest`);
}
const temple = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/TheHex/Temple1999VendorManifest")!
.VendorInfo.ItemManifest;
if (!temple.find(x => x.StoreItem == "/Lotus/StoreItems/Types/Items/MiscItems/Kuva")) {
logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/TheHex/Temple1999VendorManifest`);
}
const nakak = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Ostron/MaskSalesmanManifest")!
.VendorInfo.ItemManifest;
if (
nakak.length != 10 ||
nakak[0].StoreItem != "/Lotus/StoreItems/Upgrades/Skins/Ostron/RevenantMask" ||
nakak[1].StoreItem != "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyThumper" ||
nakak[1].ItemPrices?.length != 4 ||
nakak[2].StoreItem != "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyThumperMedium" ||
nakak[2].ItemPrices?.length != 4 ||
nakak[3].StoreItem != "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyThumperLarge" ||
nakak[3].ItemPrices?.length != 4
// The remaining offers should be computed by weighted RNG.
) {
logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Ostron/MaskSalesmanManifest`);
}
} }

View File

@ -5,9 +5,16 @@ import { config } from "./configService";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { app } from "../app"; import { app } from "../app";
import { AddressInfo } from "node:net"; import { AddressInfo } from "node:net";
import ws from "ws";
import { Account } from "../models/loginModel";
import { createAccount, createNonce, getUsernameFromEmail, isCorrectPassword } from "./loginService";
import { IDatabaseAccountJson } from "../types/loginTypes";
import { HydratedDocument } from "mongoose";
let httpServer: http.Server | undefined; let httpServer: http.Server | undefined;
let httpsServer: https.Server | undefined; let httpsServer: https.Server | undefined;
let wsServer: ws.Server | undefined;
let wssServer: ws.Server | undefined;
const tlsOptions = { const tlsOptions = {
key: fs.readFileSync("static/certs/key.pem"), key: fs.readFileSync("static/certs/key.pem"),
@ -21,10 +28,17 @@ export const startWebServer = (): void => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
httpServer = http.createServer(app); httpServer = http.createServer(app);
httpServer.listen(httpPort, () => { httpServer.listen(httpPort, () => {
wsServer = new ws.Server({ server: httpServer });
wsServer.on("connection", wsOnConnect);
logger.info("HTTP server started on port " + httpPort); logger.info("HTTP server started on port " + httpPort);
// eslint-disable-next-line @typescript-eslint/no-misused-promises // eslint-disable-next-line @typescript-eslint/no-misused-promises
httpsServer = https.createServer(tlsOptions, app); httpsServer = https.createServer(tlsOptions, app);
httpsServer.listen(httpsPort, () => { httpsServer.listen(httpsPort, () => {
wssServer = new ws.Server({ server: httpsServer });
wssServer.on("connection", wsOnConnect);
logger.info("HTTPS server started on port " + httpsPort); logger.info("HTTPS server started on port " + httpsPort);
logger.info( logger.info(
@ -61,5 +75,150 @@ export const stopWebServer = async (): Promise<void> => {
}) })
); );
} }
if (wsServer) {
promises.push(
new Promise(resolve => {
wsServer!.close(() => {
resolve();
});
})
);
}
if (wssServer) {
promises.push(
new Promise(resolve => {
wssServer!.close(() => {
resolve();
});
})
);
}
await Promise.all(promises); await Promise.all(promises);
}; };
interface IWsCustomData extends ws {
accountId?: string;
}
interface IWsMsgFromClient {
auth?: {
email: string;
password: string;
isRegister: boolean;
};
logout?: boolean;
}
interface IWsMsgToClient {
reload?: boolean;
ports?: {
http: number | undefined;
https: number | undefined;
};
config_reloaded?: boolean;
auth_succ?: {
id: string;
DisplayName: string;
Nonce: number;
};
auth_fail?: {
isRegister: boolean;
};
logged_out?: boolean;
}
const wsOnConnect = (ws: ws, _req: http.IncomingMessage): void => {
// eslint-disable-next-line @typescript-eslint/no-misused-promises
ws.on("message", async msg => {
const data = JSON.parse(String(msg)) as IWsMsgFromClient;
if (data.auth) {
let account: IDatabaseAccountJson | null = await Account.findOne({ email: data.auth.email });
if (account) {
if (isCorrectPassword(data.auth.password, account.password)) {
if (!account.Nonce) {
account.ClientType = "webui";
account.Nonce = createNonce();
await (account as HydratedDocument<IDatabaseAccountJson>).save();
}
} else {
account = null;
}
} else if (data.auth.isRegister) {
const name = await getUsernameFromEmail(data.auth.email);
account = await createAccount({
email: data.auth.email,
password: data.auth.password,
ClientType: "webui",
LastLogin: new Date(),
DisplayName: name,
Nonce: createNonce()
});
}
if (account) {
(ws as IWsCustomData).accountId = account.id;
ws.send(
JSON.stringify({
auth_succ: {
id: account.id,
DisplayName: account.DisplayName,
Nonce: account.Nonce
}
} satisfies IWsMsgToClient)
);
} else {
ws.send(
JSON.stringify({
auth_fail: {
isRegister: data.auth.isRegister
}
} satisfies IWsMsgToClient)
);
}
}
if (data.logout) {
const accountId = (ws as IWsCustomData).accountId;
(ws as IWsCustomData).accountId = undefined;
await Account.updateOne(
{
_id: accountId,
ClientType: "webui"
},
{
Nonce: 0
}
);
}
});
};
export const sendWsBroadcast = (data: IWsMsgToClient): void => {
const msg = JSON.stringify(data);
if (wsServer) {
for (const client of wsServer.clients) {
client.send(msg);
}
}
if (wssServer) {
for (const client of wssServer.clients) {
client.send(msg);
}
}
};
export const sendWsBroadcastTo = (accountId: string, data: IWsMsgToClient): void => {
const msg = JSON.stringify(data);
if (wsServer) {
for (const client of wsServer.clients) {
if ((client as IWsCustomData).accountId == accountId) {
client.send(msg);
}
}
}
if (wssServer) {
for (const client of wssServer.clients) {
if ((client as IWsCustomData).accountId == accountId) {
client.send(msg);
}
}
}
};

View File

@ -1,12 +1,13 @@
import staticWorldState from "@/static/fixed_responses/worldState/worldState.json"; import staticWorldState from "@/static/fixed_responses/worldState/worldState.json";
import fissureMissions from "@/static/fixed_responses/worldState/fissureMissions.json";
import sortieTilesets from "@/static/fixed_responses/worldState/sortieTilesets.json"; import sortieTilesets from "@/static/fixed_responses/worldState/sortieTilesets.json";
import sortieTilesetMissions from "@/static/fixed_responses/worldState/sortieTilesetMissions.json"; import sortieTilesetMissions from "@/static/fixed_responses/worldState/sortieTilesetMissions.json";
import syndicateMissions from "@/static/fixed_responses/worldState/syndicateMissions.json"; import syndicateMissions from "@/static/fixed_responses/worldState/syndicateMissions.json";
import { buildConfig } from "@/src/services/buildConfigService"; import { buildConfig } from "@/src/services/buildConfigService";
import { unixTimesInMs } from "@/src/constants/timeConstants"; import { unixTimesInMs } from "@/src/constants/timeConstants";
import { config } from "@/src/services/configService"; import { config } from "@/src/services/configService";
import { SRng } from "@/src/services/rngService"; import { getRandomElement, getRandomInt, SRng } from "@/src/services/rngService";
import { ExportRegions, ExportSyndicates, IRegion } from "warframe-public-export-plus"; import { eMissionType, ExportRegions, ExportSyndicates, IRegion } from "warframe-public-export-plus";
import { import {
ICalendarDay, ICalendarDay,
ICalendarEvent, ICalendarEvent,
@ -16,10 +17,14 @@ import {
ISortie, ISortie,
ISortieMission, ISortieMission,
ISyndicateMissionInfo, ISyndicateMissionInfo,
IWorldState ITmp,
IVoidStorm,
IWorldState,
TCircuitGameMode
} from "../types/worldStateTypes"; } from "../types/worldStateTypes";
import { version_compare } from "../helpers/inventoryHelpers"; import { toMongoDate, toOid, version_compare } from "../helpers/inventoryHelpers";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { Fissure } from "../models/worldStateModel";
const sortieBosses = [ const sortieBosses = [
"SORTIE_BOSS_HYENA", "SORTIE_BOSS_HYENA",
@ -963,6 +968,61 @@ const getCalendarSeason = (week: number): ICalendarSeason => {
}; };
}; };
// Not very faithful, but to avoid the same node coming up back-to-back (which is not valid), I've split these into 2 arrays which we're alternating between.
const voidStormMissionsA = {
VoidT1: ["CrewBattleNode519", "CrewBattleNode518", "CrewBattleNode515", "CrewBattleNode503"],
VoidT2: ["CrewBattleNode501", "CrewBattleNode534", "CrewBattleNode530"],
VoidT3: ["CrewBattleNode521", "CrewBattleNode516"],
VoidT4: [
"CrewBattleNode555",
"CrewBattleNode553",
"CrewBattleNode554",
"CrewBattleNode539",
"CrewBattleNode531",
"CrewBattleNode527"
]
};
const voidStormMissionsB = {
VoidT1: ["CrewBattleNode509", "CrewBattleNode522", "CrewBattleNode511", "CrewBattleNode512"],
VoidT2: ["CrewBattleNode535", "CrewBattleNode533"],
VoidT3: ["CrewBattleNode524", "CrewBattleNode525"],
VoidT4: [
"CrewBattleNode542",
"CrewBattleNode538",
"CrewBattleNode543",
"CrewBattleNode536",
"CrewBattleNode550",
"CrewBattleNode529"
]
};
const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => {
const activation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute;
const expiry = activation + 90 * unixTimesInMs.minute;
let accum = 0;
const rng = new SRng(new SRng(hour).randomInt(0, 100_000));
const voidStormMissions = structuredClone(hour & 1 ? voidStormMissionsA : voidStormMissionsB);
for (const tier of ["VoidT1", "VoidT1", "VoidT2", "VoidT3", "VoidT4", "VoidT4"] as const) {
const idx = rng.randomInt(0, voidStormMissions[tier].length - 1);
const node = voidStormMissions[tier][idx];
voidStormMissions[tier].splice(idx, 1);
arr.push({
_id: {
$oid:
((activation / 1000) & 0xffffffff).toString(16).padStart(8, "0") +
"0321e89b" +
(accum++).toString().padStart(8, "0")
},
Node: node,
Activation: { $date: { $numberLong: activation.toString() } },
Expiry: { $date: { $numberLong: expiry.toString() } },
ActiveMissionTier: tier
});
}
};
const doesTimeSatsifyConstraints = (timeSecs: number): boolean => { const doesTimeSatsifyConstraints = (timeSecs: number): boolean => {
if (config.worldState?.eidolonOverride) { if (config.worldState?.eidolonOverride) {
const eidolonEpoch = 1391992660; const eidolonEpoch = 1391992660;
@ -1010,6 +1070,27 @@ const doesTimeSatsifyConstraints = (timeSecs: number): boolean => {
} }
} }
if (config.worldState?.duviriOverride) {
const duviriMoods = ["sorrow", "fear", "joy", "anger", "envy"];
const desiredMood = duviriMoods.indexOf(config.worldState.duviriOverride);
if (desiredMood == -1) {
logger.warn(`ignoring invalid config value for worldState.duviriOverride`, {
value: config.worldState.duviriOverride,
valid_values: duviriMoods
});
} else {
const moodIndex = Math.trunc(timeSecs / 7200);
const moodStart = moodIndex * 7200;
const moodEnd = moodStart + 7200;
if (
moodIndex % 5 != desiredMood ||
isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, moodEnd * 1000)
) {
return false;
}
}
}
return true; return true;
}; };
@ -1031,20 +1112,18 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
Alerts: [], Alerts: [],
Sorties: [], Sorties: [],
LiteSorties: [], LiteSorties: [],
ActiveMissions: [],
GlobalUpgrades: [], GlobalUpgrades: [],
VoidStorms: [],
EndlessXpChoices: [], EndlessXpChoices: [],
KnownCalendarSeasons: [], KnownCalendarSeasons: [],
...staticWorldState, ...staticWorldState,
SyndicateMissions: [...staticWorldState.SyndicateMissions] SyndicateMissions: [...staticWorldState.SyndicateMissions]
}; };
// Omit void fissures for versions prior to Dante Unbound to avoid script errors. // Old versions seem to really get hung up on not being able to load these.
if (buildLabel && version_compare(buildLabel, "2024.03.24.20.00") < 0) { if (buildLabel && version_compare(buildLabel, "2017.10.12.17.04") < 0) {
worldState.ActiveMissions = []; worldState.PVPChallengeInstances = [];
if (version_compare(buildLabel, "2017.10.12.17.04") < 0) {
// Old versions seem to really get hung up on not being able to load these.
worldState.PVPChallengeInstances = [];
}
} }
if (config.worldState?.starDays) { if (config.worldState?.starDays) {
@ -1228,12 +1307,27 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
worldState.KnownCalendarSeasons.push(getCalendarSeason(week + 1)); worldState.KnownCalendarSeasons.push(getCalendarSeason(week + 1));
} }
// Sentient Anomaly cycling every 30 minutes // Void Storms
const hour = Math.trunc(timeMs / unixTimesInMs.hour);
const overLastHourStormExpiry = hour * unixTimesInMs.hour + 10 * unixTimesInMs.minute;
const thisHourStormActivation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute;
if (overLastHourStormExpiry > timeMs) {
pushVoidStorms(worldState.VoidStorms, hour - 2);
}
pushVoidStorms(worldState.VoidStorms, hour - 1);
if (isBeforeNextExpectedWorldStateRefresh(timeMs, thisHourStormActivation)) {
pushVoidStorms(worldState.VoidStorms, hour);
}
// Sentient Anomaly + Xtra Cheese cycles
const halfHour = Math.trunc(timeMs / (unixTimesInMs.hour / 2)); const halfHour = Math.trunc(timeMs / (unixTimesInMs.hour / 2));
const tmp = { const hourInSeconds = 3600;
const cheeseInterval = hourInSeconds * 8;
const cheeseDuration = hourInSeconds * 2;
const cheeseIndex = Math.trunc(timeSecs / cheeseInterval);
const tmp: ITmp = {
cavabegin: "1690761600", cavabegin: "1690761600",
PurchasePlatformLockEnabled: true, PurchasePlatformLockEnabled: true,
tcsn: true,
pgr: { pgr: {
ts: "1732572900", ts: "1732572900",
en: "CUSTOM DECALS @ ZEVILA", en: "CUSTOM DECALS @ ZEVILA",
@ -1254,13 +1348,39 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
}, },
ennnd: true, ennnd: true,
mbrt: true, mbrt: true,
fbst: {
a: cheeseIndex * cheeseInterval, // This has a bug where the client shows a negative time for "Xtra cheese starts in ..." until it refreshes the world state. This is because we're only providing the new activation as soon as that time/date is reached. However, this is 100% faithful to live.
e: cheeseIndex * cheeseInterval + cheeseDuration,
n: (cheeseIndex + 1) * cheeseInterval
},
sfn: [550, 553, 554, 555][halfHour % 4] sfn: [550, 553, 554, 555][halfHour % 4]
}; };
if (Array.isArray(config.worldState?.circuitGameModes)) {
tmp.edg = config.worldState.circuitGameModes as TCircuitGameMode[];
}
worldState.Tmp = JSON.stringify(tmp); worldState.Tmp = JSON.stringify(tmp);
return worldState; return worldState;
}; };
export const populateFissures = async (worldState: IWorldState): Promise<void> => {
const fissures = await Fissure.find({});
for (const fissure of fissures) {
const meta = ExportRegions[fissure.Node];
worldState.ActiveMissions.push({
_id: toOid(fissure._id),
Region: meta.systemIndex + 1,
Seed: 1337,
Activation: toMongoDate(fissure.Activation),
Expiry: toMongoDate(fissure.Expiry),
Node: fissure.Node,
MissionType: eMissionType[meta.missionIndex].tag,
Modifier: fissure.Modifier,
Hard: fissure.Hard
});
}
};
export const idToBountyCycle = (id: string): number => { export const idToBountyCycle = (id: string): number => {
return Math.trunc((parseInt(id.substring(0, 8), 16) * 1000) / 9000_000); return Math.trunc((parseInt(id.substring(0, 8), 16) * 1000) / 9000_000);
}; };
@ -1388,3 +1508,57 @@ const nightwaveTagToSeason: Record<string, number> = {
RadioLegionIntermissionSyndicate: 1, // Intermission I RadioLegionIntermissionSyndicate: 1, // Intermission I
RadioLegionSyndicate: 0 // The Wolf of Saturn Six RadioLegionSyndicate: 0 // The Wolf of Saturn Six
}; };
export const updateWorldStateCollections = async (): Promise<void> => {
const fissures = await Fissure.find();
const activeNodes = new Set<string>();
const tierToFurthestExpiry: Record<string, number> = {
VoidT1: 0,
VoidT2: 0,
VoidT3: 0,
VoidT4: 0,
VoidT5: 0,
VoidT6: 0,
VoidT1Hard: 0,
VoidT2Hard: 0,
VoidT3Hard: 0,
VoidT4Hard: 0,
VoidT5Hard: 0,
VoidT6Hard: 0
};
for (const fissure of fissures) {
activeNodes.add(fissure.Node);
const key = fissure.Modifier + (fissure.Hard ? "Hard" : "");
tierToFurthestExpiry[key] = Math.max(tierToFurthestExpiry[key], fissure.Expiry.getTime());
}
const deadline = Date.now() - 6 * unixTimesInMs.minute;
for (const [tier, expiry] of Object.entries(tierToFurthestExpiry)) {
if (expiry < deadline) {
const numFissures = getRandomInt(1, 3);
for (let i = 0; i != numFissures; ++i) {
const modifier = tier.replace("Hard", "") as
| "VoidT1"
| "VoidT2"
| "VoidT3"
| "VoidT4"
| "VoidT5"
| "VoidT6";
let node: string;
do {
node = getRandomElement(fissureMissions[modifier])!;
} while (activeNodes.has(node));
activeNodes.add(node);
await Fissure.insertOne({
Activation: new Date(),
Expiry: new Date(Date.now() + getRandomInt(60, 120) * unixTimesInMs.minute),
Node: node,
Modifier: modifier,
Hard: tier.indexOf("Hard") != -1 ? true : undefined
});
}
}
}
};

View File

@ -234,7 +234,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
HandlerPoints: number; HandlerPoints: number;
MiscItems: IMiscItem[]; MiscItems: IMiscItem[];
HasOwnedVoidProjectionsPreviously?: boolean; HasOwnedVoidProjectionsPreviously?: boolean;
ChallengesFixVersion: number; ChallengesFixVersion?: number;
ChallengeProgress: IChallengeProgress[]; ChallengeProgress: IChallengeProgress[];
RawUpgrades: IRawUpgrade[]; RawUpgrades: IRawUpgrade[];
ReceivedStartingGear: boolean; ReceivedStartingGear: boolean;
@ -641,11 +641,11 @@ export interface IFocusUpgrade {
} }
export interface IFocusXP { export interface IFocusXP {
AP_POWER: number; AP_POWER?: number;
AP_TACTIC: number; AP_TACTIC?: number;
AP_DEFENSE: number; AP_DEFENSE?: number;
AP_ATTACK: number; AP_ATTACK?: number;
AP_WARD: number; AP_WARD?: number;
} }
export type TFocusPolarity = keyof IFocusXP; export type TFocusPolarity = keyof IFocusXP;

View File

@ -2,7 +2,7 @@ import { Types } from "mongoose";
export interface IAccountAndLoginResponseCommons { export interface IAccountAndLoginResponseCommons {
DisplayName: string; DisplayName: string;
CountryCode: string; CountryCode?: string;
ClientType?: string; ClientType?: string;
CrossPlatformAllowed?: boolean; CrossPlatformAllowed?: boolean;
ForceLogoutVersion?: number; ForceLogoutVersion?: number;

View File

@ -9,9 +9,10 @@ export interface IWorldState {
Sorties: ISortie[]; Sorties: ISortie[];
LiteSorties: ILiteSortie[]; LiteSorties: ILiteSortie[];
SyndicateMissions: ISyndicateMissionInfo[]; SyndicateMissions: ISyndicateMissionInfo[];
GlobalUpgrades: IGlobalUpgrade[];
ActiveMissions: IFissure[]; ActiveMissions: IFissure[];
GlobalUpgrades: IGlobalUpgrade[];
NodeOverrides: INodeOverride[]; NodeOverrides: INodeOverride[];
VoidStorms: IVoidStorm[];
PVPChallengeInstances: IPVPChallengeInstance[]; PVPChallengeInstances: IPVPChallengeInstance[];
EndlessXpChoices: IEndlessXpChoice[]; EndlessXpChoices: IEndlessXpChoice[];
SeasonInfo?: { SeasonInfo?: {
@ -85,6 +86,14 @@ export interface IFissure {
Hard?: boolean; Hard?: boolean;
} }
export interface IFissureDatabase {
Activation: Date;
Expiry: Date;
Node: string;
Modifier: "VoidT1" | "VoidT2" | "VoidT3" | "VoidT4" | "VoidT5" | "VoidT6";
Hard?: boolean;
}
export interface INodeOverride { export interface INodeOverride {
_id: IOid; _id: IOid;
Activation?: IMongoDate; Activation?: IMongoDate;
@ -131,6 +140,14 @@ export interface ILiteSortie {
}[]; }[];
} }
export interface IVoidStorm {
_id: IOid;
Node: string;
Activation: IMongoDate;
Expiry: IMongoDate;
ActiveMissionTier: string;
}
export interface IPVPChallengeInstance { export interface IPVPChallengeInstance {
_id: IOid; _id: IOid;
challengeTypeRefID: string; challengeTypeRefID: string;
@ -182,3 +199,48 @@ export interface ICalendarEvent {
dialogueName?: string; dialogueName?: string;
dialogueConvo?: string; dialogueConvo?: string;
} }
export type TCircuitGameMode =
| "Survival"
| "VoidFlood"
| "Excavation"
| "Defense"
| "Exterminate"
| "Assassination"
| "Alchemy";
export interface ITmp {
cavabegin: string;
PurchasePlatformLockEnabled: boolean; // Seems unused
pgr: IPgr;
ennnd?: boolean; // True if 1999 demo is available (no effect for >=38.6.0)
mbrt?: boolean; // Related to mobile app rating request
fbst: IFbst;
sfn: number;
edg?: TCircuitGameMode[]; // The Circuit game modes overwrite
}
interface IPgr {
ts: string;
en: string;
fr: string;
it: string;
de: string;
es: string;
pt: string;
ru: string;
pl: string;
uk: string;
tr: string;
ja: string;
zh: string;
ko: string;
tc: string;
th: string;
}
interface IFbst {
a: number;
e: number;
n: number;
}

View File

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

View File

@ -1,300 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5f456e01c96976e97d6b802e"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/EntratiFragmentVendorProductsManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Deimos/SeriglassShard",
"ItemPrices": [
{
"ItemCount": 20,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e8390"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileDeimosBouncy",
"ItemPrices": [
{
"ItemCount": 50,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e8391"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileDeimosBreakthrough",
"ItemPrices": [
{
"ItemCount": 50,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e8392"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileDeimosCatacombs",
"ItemPrices": [
{
"ItemCount": 50,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e8393"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileDeimosDownfall",
"ItemPrices": [
{
"ItemCount": 50,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e8394"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileDeimosObsession",
"ItemPrices": [
{
"ItemCount": 50,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e8395"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileDeimosTunnels",
"ItemPrices": [
{
"ItemCount": 50,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e8396"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Deimos/FatherTokenShipDeco",
"ItemPrices": [
{
"ItemCount": 10,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonA",
"ProductCategory": "MiscItems"
},
{
"ItemCount": 5,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e83f1"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Deimos/LisetPropEntratiLamp",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentCommonB",
"ItemCount": 12,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e83f2"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Deimos/LisetPropInfestedCrate",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentCommonA",
"ItemCount": 11,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e83f3"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Deimos/LisetPropInfestedCystC",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e83f4"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/StoreItems/AvatarImages/RequiemRisGlyph",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b10ba592c4c95e83f5"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Deimos/MotherTokenShipDeco",
"ItemPrices": [
{
"ItemCount": 10,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonB",
"ProductCategory": "MiscItems"
},
{
"ItemCount": 5,
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentRareA",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e83f6"
}
}
],
"PropertyTextHash": "DB953EE163A65B3BCC0552902321D791",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,241 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5f456e01c96976e97d6b8009"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/HivemindCommisionsManifestFishmonger",
"ItemManifest": [
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Daughter/DaughterTaskC",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishFPartItem",
"ItemCount": 6,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
"ItemCount": 16,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 63978959,
"Id": {
"$oid": "66fd60b10ba592c4c95e82cc"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Daughter/DaughterTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishBPartItem",
"ItemCount": 5,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishDPartItem",
"ItemCount": 4,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 3808064409,
"Id": {
"$oid": "66fd60b10ba592c4c95e82cd"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Daughter/DaughterTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishEPartItem",
"ItemCount": 2,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
"ItemCount": 2,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 3849710569,
"Id": {
"$oid": "66fd60b10ba592c4c95e82d0"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Daughter/DaughterTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosGenericInfestedFishPartItem",
"ItemCount": 5,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
"ItemCount": 4,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 1687111317,
"Id": {
"$oid": "66fd60b10ba592c4c95e82d1"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Daughter/DaughterTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishAPartItem",
"ItemCount": 4,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishBPartItem",
"ItemCount": 4,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2267414276,
"Id": {
"$oid": "66fd60b10ba592c4c95e82d2"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Daughter/DaughterTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosGenericInfestedFishPartItem",
"ItemCount": 6,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosGenericSharedFishPartItem",
"ItemCount": 6,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 1497494256,
"Id": {
"$oid": "66fd60b10ba592c4c95e82d3"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Daughter/DaughterTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosGenericInfestedFishPartItem",
"ItemCount": 5,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
"ItemCount": 2,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2883527039,
"Id": {
"$oid": "66fd60b10ba592c4c95e82d4"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Daughter/DaughterTaskC",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishGPartItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
"ItemCount": 12,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 4116691539,
"Id": {
"$oid": "66fd60b10ba592c4c95e82d5"
}
}
],
"PropertyTextHash": "54B6992C6314367F8EEA74B7F1A1C352",
"RandomSeedType": "VRST_FLAVOUR_TEXT",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,287 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5f456e03c96976e97d6b80a3"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/HivemindCommisionsManifestPetVendor",
"ItemManifest": [
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Son/SonTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedMaggotRare",
"ItemCount": 2,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedMaggotCommon",
"ItemCount": 4,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2707699975,
"Id": {
"$oid": "66fd60b10ba592c4c95e8897"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Son/SonTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedPredatorCommon",
"ItemCount": 2,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedMaggotCommon",
"ItemCount": 4,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 3610714639,
"Id": {
"$oid": "66fd60b10ba592c4c95e8898"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Son/SonTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedPredatorCommon",
"ItemCount": 2,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedMaggotRare",
"ItemCount": 1,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 1782149988,
"Id": {
"$oid": "66fd60b10ba592c4c95e8899"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Son/SonTaskC",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedMergooCommon",
"ItemCount": 3,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2149416825,
"Id": {
"$oid": "66fd60b10ba592c4c95e889a"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Son/SonTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedCritterRare",
"ItemCount": 2,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedKdriveUncommon",
"ItemCount": 2,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 890863265,
"Id": {
"$oid": "66fd60b10ba592c4c95e889b"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Son/SonTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedCritterCommon",
"ItemCount": 4,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedPredatorCommon",
"ItemCount": 4,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2507606934,
"Id": {
"$oid": "66fd60b10ba592c4c95e889c"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Son/SonTaskC",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedPredatorRare",
"ItemCount": 5,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 1037784729,
"Id": {
"$oid": "66fd60b10ba592c4c95e889e"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Son/SonTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedMaggotCommon",
"ItemCount": 4,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedCritterCommon",
"ItemCount": 4,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2048707501,
"Id": {
"$oid": "66fd60b10ba592c4c95e889f"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Son/SonTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedKdriveRare",
"ItemCount": 2,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedPredatorCommon",
"ItemCount": 2,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 4038149313,
"Id": {
"$oid": "66fd60b10ba592c4c95e88a0"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Son/SonTaskD",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedMergooCommon",
"ItemCount": 3,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/AnimalTagInfestedPredatorRare",
"ItemCount": 3,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_3",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2155290001,
"Id": {
"$oid": "66fd60b10ba592c4c95e88a1"
}
}
],
"PropertyTextHash": "61E66B4E9E5A121DD06A476AE2A81B24",
"RandomSeedType": "VRST_FLAVOUR_TEXT",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,312 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5f456e01c96976e97d6b7ff1"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/HivemindCommisionsManifestProspector",
"ItemManifest": [
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Otak/OtakTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonOreAItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonGemBItem",
"ItemCount": 8,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 1370972414,
"Id": {
"$oid": "66fd60b20ba592c4c95e8ef8"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Otak/OtakTaskC",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonOreBItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosUncommonGemAItem",
"ItemCount": 8,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosUncommonOreAItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2361790143,
"Id": {
"$oid": "66fd60b20ba592c4c95e8ef9"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Otak/OtakTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonGemAItem",
"ItemCount": 6,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonOreAItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 472210739,
"Id": {
"$oid": "66fd60b20ba592c4c95e8efb"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Otak/OtakTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonOreBItem",
"ItemCount": 12,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonOreAItem",
"ItemCount": 15,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 3072462886,
"Id": {
"$oid": "66fd60b20ba592c4c95e8efd"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Otak/OtakTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonGemAItem",
"ItemCount": 8,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonOreAItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 767765909,
"Id": {
"$oid": "66fd60b20ba592c4c95e8efe"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Otak/OtakTaskD",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosEidolonGemAItem",
"ItemCount": 5,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosEidolonGemBItem",
"ItemCount": 2,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosRareOreAItem",
"ItemCount": 22,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_3",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 512512880,
"Id": {
"$oid": "66fd60b20ba592c4c95e8eff"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Otak/OtakTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonOreAItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonGemAItem",
"ItemCount": 6,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2037734419,
"Id": {
"$oid": "66fd60b20ba592c4c95e8f00"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Otak/OtakTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosUncommonOreAItem",
"ItemCount": 13,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonOreAItem",
"ItemCount": 8,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 1433662587,
"Id": {
"$oid": "66fd60b20ba592c4c95e8f01"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Otak/OtakTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonOreAItem",
"ItemCount": 12,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonGemAItem",
"ItemCount": 8,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 1618492734,
"Id": {
"$oid": "66fd60b20ba592c4c95e8f02"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Otak/OtakTaskD",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosUncommonGemAItem",
"ItemCount": 7,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonGemBItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosRareOreAItem",
"ItemCount": 12,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_3",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 4032699594,
"Id": {
"$oid": "66fd60b20ba592c4c95e8f03"
}
}
],
"PropertyTextHash": "0AC3C284471037011B36EC51238D13A9",
"RandomSeedType": "VRST_FLAVOUR_TEXT",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,223 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5f456e03c96976e97d6b80d2"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/HivemindCommisionsManifestTokenVendor",
"ItemManifest": [
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Grandmother/GrandmotherTaskD",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentCommonC",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentCommonA",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonB",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonA",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 1415858946,
"Id": {
"$oid": "670a47b1872b2325705e746c"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Grandmother/GrandmotherTaskD",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentCommonB",
"ItemCount": 2,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonA",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentCommonA",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonB",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 3178511462,
"Id": {
"$oid": "670a47b1872b2325705e746e"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Grandmother/GrandmotherTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonA",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentCommonC",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 3313207881,
"Id": {
"$oid": "670a47b1872b2325705e7471"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Grandmother/GrandmotherTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentCommonB",
"ItemCount": 2,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2241288767,
"Id": {
"$oid": "670a47b1872b2325705e7472"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Grandmother/GrandmotherTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonB",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 3395082536,
"Id": {
"$oid": "670a47b1872b2325705e7473"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Grandmother/GrandmotherTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentCommonC",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonB",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 493457277,
"Id": {
"$oid": "670a47b1872b2325705e7474"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Grandmother/GrandmotherTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentUncommonB",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Deimos/EntratiFragmentCommonB",
"ItemCount": 2,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 4225814786,
"Id": {
"$oid": "670a47b1872b2325705e7475"
}
}
],
"PropertyTextHash": "58884EC7ECE7D22AD4BD9E9B436C37A8",
"RandomSeedType": "VRST_FLAVOUR_TEXT",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,254 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5f456e02c96976e97d6b8049"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/HivemindCommisionsManifestWeaponsmith",
"ItemManifest": [
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Father/FatherTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfGorgaricusSeedItem",
"ItemCount": 16,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2438288725,
"Id": {
"$oid": "66fd60b00ba592c4c95e7caf"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Father/FatherTaskC",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Game/FishBait/Infested/OrokinFishBaitA",
"ItemCount": 6,
"ProductCategory": "Consumables"
},
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfMapricoFruitItem",
"ItemCount": 21,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Game/FishBait/Infested/InfestedFishBaitA",
"ItemCount": 6,
"ProductCategory": "Consumables"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2431016296,
"Id": {
"$oid": "66fd60b00ba592c4c95e7cb2"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Father/FatherTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfMapricoFruitItem",
"ItemCount": 16,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 18484856,
"Id": {
"$oid": "66fd60b00ba592c4c95e7cb3"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Father/FatherTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfMapricoFruitItem",
"ItemCount": 14,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2278976516,
"Id": {
"$oid": "66fd60b00ba592c4c95e7cb4"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Father/FatherTaskC",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Game/FishBait/Infested/OrokinFishBaitA",
"ItemCount": 7,
"ProductCategory": "Consumables"
},
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/OrbStoneItem",
"ItemCount": 25,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Game/FishBait/Infested/InfestedFishBaitA",
"ItemCount": 6,
"ProductCategory": "Consumables"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 3150323898,
"Id": {
"$oid": "66fd60b00ba592c4c95e7cb5"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Father/FatherTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfMapricoFruitItem",
"ItemCount": 8,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 3971758486,
"Id": {
"$oid": "66fd60b00ba592c4c95e7cb6"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Father/FatherTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfGorgaricusSeedItem",
"ItemCount": 17,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/OrbStoneItem",
"ItemCount": 18,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2512835718,
"Id": {
"$oid": "66fd60b00ba592c4c95e7cb7"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Father/FatherTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/OrbStoneItem",
"ItemCount": 8,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 825411410,
"Id": {
"$oid": "66fd60b00ba592c4c95e7cb8"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Father/FatherTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfGorgaricusSeedItem",
"ItemCount": 22,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/OrbStoneItem",
"ItemCount": 12,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2383349671,
"Id": {
"$oid": "66fd60b00ba592c4c95e7cb9"
}
}
],
"PropertyTextHash": "CE9413585756FA39B793A9814E74E49F",
"RandomSeedType": "VRST_FLAVOUR_TEXT",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,286 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5fb70313c96976e97d6be6fe"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/HivemindTokenVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Remedies/RemedySonB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishBPartItem",
"ItemCount": 36,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishEPartItem",
"ItemCount": 36,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 379215713,
"Id": {
"$oid": "66fd60b20ba592c4c95e9308"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Remedies/RemedyMotherB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosGenericInfestedFishPartItem",
"ItemCount": 80,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfGorgaricusSeedItem",
"ItemCount": 32,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
"ItemCount": 28,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2534781881,
"Id": {
"$oid": "66fd60b20ba592c4c95e9309"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Remedies/RemedyDaughterB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosUncommonGemAItem",
"ItemCount": 28,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
"ItemCount": 32,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishAPartItem",
"ItemCount": 32,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 1507786123,
"Id": {
"$oid": "66fd60b20ba592c4c95e930a"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Remedies/RemedySonA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosRareGemAItem",
"ItemCount": 15,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonGemAItem",
"ItemCount": 30,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfGorgaricusSeedItem",
"ItemCount": 21,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 616241643,
"Id": {
"$oid": "66fd60b20ba592c4c95e930b"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Remedies/RemedyOtakA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishBPartItem",
"ItemCount": 21,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
"ItemCount": 27,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishEPartItem",
"ItemCount": 27,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2888479655,
"Id": {
"$oid": "66fd60b20ba592c4c95e930c"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Remedies/RemedyGrandmotherA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonGemBItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishBPartItem",
"ItemCount": 28,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfGorgaricusSeedItem",
"ItemCount": 24,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosCommonGemAItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2874726481,
"Id": {
"$oid": "66fd60b20ba592c4c95e930d"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Remedies/RemedyFatherA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosGenericSharedFishPartItem",
"ItemCount": 75,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Deimos/DeimosUncommonGemAItem",
"ItemCount": 27,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/OrbStoneItem",
"ItemCount": 30,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 274676857,
"Id": {
"$oid": "66fd60b20ba592c4c95e930e"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/Deimos/Remedies/RemedyDaughterA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/InfestedMicroplanet/Resources/InfGorgaricusSeedItem",
"ItemCount": 24,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishBPartItem",
"ItemCount": 30,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Deimos/FishParts/DeimosGenericSharedFishPartItem",
"ItemCount": 51,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"LocTagRandSeed": 2487943761,
"Id": {
"$oid": "66fd60b20ba592c4c95e930f"
}
}
],
"PropertyTextHash": "C34BF0BEDEAF7CBB0EEBFFECDFD6646D",
"RandomSeedType": "VRST_FLAVOUR_TEXT",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,136 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5f456e02c96976e97d6b8080"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/PetVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Deimos/AnimalTagInfestedNexiferaRare",
"PremiumPrice": [35, 35],
"Bin": "BIN_0",
"QuantityMultiplier": 5,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e89f6"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Deimos/AnimalTagInfestedNexiferaUncommon",
"PremiumPrice": [22, 22],
"Bin": "BIN_0",
"QuantityMultiplier": 5,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e89f7"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Deimos/AnimalTagInfestedMergooUncommon",
"PremiumPrice": [28, 28],
"Bin": "BIN_0",
"QuantityMultiplier": 5,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e89f8"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Deimos/AnimalTagInfestedKdriveUncommon",
"PremiumPrice": [25, 25],
"Bin": "BIN_0",
"QuantityMultiplier": 5,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e89f9"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Deimos/AnimalTagInfestedZongroCommon",
"PremiumPrice": [14, 14],
"Bin": "BIN_0",
"QuantityMultiplier": 5,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e89fa"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Deimos/AnimalTagInfestedPredatorCommon",
"PremiumPrice": [12, 12],
"Bin": "BIN_0",
"QuantityMultiplier": 5,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e89fb"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Deimos/AnimalTagInfestedMergooCommon",
"PremiumPrice": [13, 13],
"Bin": "BIN_0",
"QuantityMultiplier": 5,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e89fc"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Deimos/AnimalTagInfestedKdriveCommon",
"PremiumPrice": [14, 14],
"Bin": "BIN_0",
"QuantityMultiplier": 5,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b10ba592c4c95e89fd"
}
}
],
"PropertyTextHash": "F14C6B6A61D7585A10537995661F5220",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,321 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "64493ca759e9b164c86a2e14"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Duviri/AcrithisVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Items/DangerRoom/DangerRoomTileDuviriDragonArena",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriDragonDropItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_5",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b00ba592c4c95e7d88"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Components/FormaBlueprint",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriDragonDropItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b00ba592c4c95e7deb"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/UtilityUnlocker",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriDragonDropItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b00ba592c4c95e7dec"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriDragonDropItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 5000,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b00ba592c4c95e7ded"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponUtilityUnlocker",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriDragonDropItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b00ba592c4c95e7dee"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriDragonDropItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 5000,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "670c5e12576f461f1e5e739c"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Plastids",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriPlantItemD",
"ItemCount": 40,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": true,
"Id": {
"$oid": "6710c312fa0b2c5cd85e73c3"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Duviri/DUVxPlanterHangingPot",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriPlantItemE",
"ItemCount": 51,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6710c312fa0b2c5cd85e73c6"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Duviri/DUVxPlanterPotB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriRockItem",
"ItemCount": 44,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6710c312fa0b2c5cd85e73c7"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/NeuralSensor",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriPlantItemA",
"ItemCount": 52,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 3,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": true,
"Id": {
"$oid": "6710c312fa0b2c5cd85e73c8"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/ControlModule",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriPlantItemF",
"ItemCount": 42,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 3,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": true,
"Id": {
"$oid": "6710c312fa0b2c5cd85e73c9"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/PhotoboothTileDuviriArenaOpera",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriProcessedItem",
"ItemCount": 240,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b00ba592c4c95e7ddd"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/CosmeticEnhancers/Utility/HealthWhileUsingChanneledAbilities",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriDragonDropItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_3",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b00ba592c4c95e7e01"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Boons/DuviriVendorBoonItem",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/Duviri/Resource/DuviriPlantItemG",
"ItemCount": 50,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_4",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": true,
"Id": {
"$oid": "6711a412ba1ba01e405e739c"
}
}
],
"PropertyTextHash": "9EE40048EB685549ACA3D01AB1F65BF2",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,245 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "6579d82b553a20c6fc0067ca"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/EntratiLabs/EntratiLabVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalAmar",
"Bin": "BIN_3",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"Affiliation": "EntratiLabSyndicate",
"MinAffiliationRank": 5,
"ReductionPerPositiveRank": 0,
"IncreasePerNegativeRank": 0,
"StandingCost": 30000,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e920d"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalBoreal",
"Bin": "BIN_3",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"Affiliation": "EntratiLabSyndicate",
"MinAffiliationRank": 5,
"ReductionPerPositiveRank": 0,
"IncreasePerNegativeRank": 0,
"StandingCost": 30000,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e920e"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalNira",
"Bin": "BIN_3",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"Affiliation": "EntratiLabSyndicate",
"MinAffiliationRank": 5,
"ReductionPerPositiveRank": 0,
"IncreasePerNegativeRank": 0,
"StandingCost": 30000,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e920f"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/EntratiLabs/ORKxLabStool",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabDogTagUncommon",
"ItemCount": 2,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabMiscItemA",
"ItemCount": 22,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/MurmurItem",
"ItemCount": 18,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9270"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/EntratiLabs/ORKxLabChairA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/MurmurItem",
"ItemCount": 15,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabMiscItemA",
"ItemCount": 19,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabMiscItemB",
"ItemCount": 19,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9271"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/EntratiLabs/ORKxLabLightWallCandleA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/MurmurItem",
"ItemCount": 12,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabDogTagCommon",
"ItemCount": 3,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9272"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/EntratiLabs/ORKxLabLightChandelierD",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabMiscItemB",
"ItemCount": 8,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabDogTagCommon",
"ItemCount": 3,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9273"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/EntratiLabs/ORKxLabLightChandelierB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabMiscItemA",
"ItemCount": 12,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabDogTagCommon",
"ItemCount": 2,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9274"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/EntratiLabs/ORKxLabLightChandelierA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/MurmurItem",
"ItemCount": 15,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabMiscItemA",
"ItemCount": 13,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9275"
}
}
],
"PropertyTextHash": "44DA3839E6F7BDB32ACED53F2B0BE14E",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,97 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "6579d82b553a20c6fc0067ae"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/EntratiLabs/EntratiLabsCommisionsManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/EntratiLabs/LoidTaskC",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabMiscItemB",
"ItemCount": 17,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/MurmurItem",
"ItemCount": 30,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "670a2b928ac7854ac55e73d3"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/EntratiLabs/LoidTaskB",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/MurmurItem",
"ItemCount": 20,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/EntratiLabMiscItemA",
"ItemCount": 228,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "670a2b928ac7854ac55e73d4"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/Tasks/EntratiLabs/LoidTaskA",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Gameplay/EntratiLab/Resources/MurmurItem",
"ItemCount": 15,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Gameplay/Zariman/Resources/ZarimanMiscItemB",
"ItemCount": 1,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "670a2b928ac7854ac55e73d5"
}
}
],
"PropertyTextHash": "60C4D85A8DE5E6538AD23CDDFEEF0422",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,244 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5fb70313c96976e97d6be787"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Hubs/RailjackCrewMemberVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/SteelMeridianCrewMemberGeneratorStrong",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/RailjackMiscItems/IsosRailjackItem",
"ItemCount": 2220,
"ProductCategory": "MiscItems"
}
],
"RegularPrice": [2180000, 2180000],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"Affiliation": "SteelMeridianSyndicate",
"MinAffiliationRank": 0,
"ReductionPerPositiveRank": 0.1,
"IncreasePerNegativeRank": 0.5,
"AllowMultipurchase": false,
"LocTagRandSeed": 4185144421,
"Id": {
"$oid": "670daf92d21f34757a5e73da"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/NewLokaCrewMemberGeneratorStrong",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/RailjackMiscItems/IsosRailjackItem",
"ItemCount": 2130,
"ProductCategory": "MiscItems"
}
],
"RegularPrice": [1890000, 1890000],
"Bin": "BIN_2",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"Affiliation": "NewLokaSyndicate",
"MinAffiliationRank": 0,
"ReductionPerPositiveRank": 0.1,
"IncreasePerNegativeRank": 0.5,
"AllowMultipurchase": false,
"LocTagRandSeed": 496053258,
"Id": {
"$oid": "670daf92d21f34757a5e73db"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/SteelMeridianCrewMemberGeneratorMediumVersionTwo",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/RailjackMiscItems/IsosRailjackItem",
"ItemCount": 440,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"Affiliation": "SteelMeridianSyndicate",
"MinAffiliationRank": 0,
"ReductionPerPositiveRank": 0.1,
"IncreasePerNegativeRank": 0.5,
"AllowMultipurchase": false,
"LocTagRandSeed": 2078883475,
"Id": {
"$oid": "670daf92d21f34757a5e73dc"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/NewLokaCrewMemberGeneratorMediumVersionTwo",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/RailjackMiscItems/AsteriteRailjackItem",
"ItemCount": 730,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"Affiliation": "NewLokaSyndicate",
"MinAffiliationRank": 0,
"ReductionPerPositiveRank": 0.1,
"IncreasePerNegativeRank": 0.5,
"AllowMultipurchase": false,
"LocTagRandSeed": 3890380934,
"Id": {
"$oid": "670daf92d21f34757a5e73dd"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/CephalonSudaCrewMemberGeneratorMediumVersionTwo",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/RailjackMiscItems/AsteriteRailjackItem",
"ItemCount": 720,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"Affiliation": "CephalonSudaSyndicate",
"MinAffiliationRank": 0,
"ReductionPerPositiveRank": 0.1,
"IncreasePerNegativeRank": 0.5,
"AllowMultipurchase": false,
"LocTagRandSeed": 3425148044,
"Id": {
"$oid": "670daf92d21f34757a5e73de"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/ArbitersCrewMemberGeneratorMediumVersionTwo",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/RailjackMiscItems/CubicsRailjackItem",
"ItemCount": 6500,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"Affiliation": "ArbitersSyndicate",
"MinAffiliationRank": 0,
"ReductionPerPositiveRank": 0.1,
"IncreasePerNegativeRank": 0.5,
"AllowMultipurchase": false,
"LocTagRandSeed": 2472754512,
"Id": {
"$oid": "670daf92d21f34757a5e73df"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/PerrinCrewMemberGeneratorVersionTwo",
"RegularPrice": [105000, 105000],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"Affiliation": "PerrinSyndicate",
"MinAffiliationRank": 0,
"ReductionPerPositiveRank": 0.1,
"IncreasePerNegativeRank": 0.5,
"AllowMultipurchase": false,
"LocTagRandSeed": 966238763,
"Id": {
"$oid": "670daf92d21f34757a5e73e0"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/NewLokaCrewMemberGeneratorVersionTwo",
"RegularPrice": [120000, 120000],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"Affiliation": "NewLokaSyndicate",
"MinAffiliationRank": 0,
"ReductionPerPositiveRank": 0.1,
"IncreasePerNegativeRank": 0.5,
"AllowMultipurchase": false,
"LocTagRandSeed": 356717213,
"Id": {
"$oid": "670daf92d21f34757a5e73e1"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Game/CrewShip/CrewMember/ArbitersCrewMemberGeneratorVersionTwo",
"RegularPrice": [120000, 120000],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"PurchaseQuantityLimit": 1,
"Affiliation": "ArbitersSyndicate",
"MinAffiliationRank": 0,
"ReductionPerPositiveRank": 0.1,
"IncreasePerNegativeRank": 0.5,
"AllowMultipurchase": false,
"LocTagRandSeed": 1969797050,
"Id": {
"$oid": "670daf92d21f34757a5e73e2"
}
}
],
"PropertyTextHash": "BE543CCC0A4F50A1D80CD2B523796EAE",
"RandomSeedType": "VRST_FLAVOUR_TEXT",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,301 +0,0 @@
{
"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

@ -1,188 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "67dadc30e4b6e0e5979c8d6a"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/TheHex/Nova1999ConquestShopManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/1999StickersPackEchoesArchimedea",
"ItemPrices": [
{
"ItemCount": 10,
"ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67db32b983b2ad79a9c1c18c"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/1999StickersPackEchoesArchimedeaFree",
"ItemPrices": [
{
"ItemCount": 1,
"ItemType": "/Lotus/Types/Items/MiscItems/1999FreeStickersPack",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67db32b983b2ad79a9c1c18d"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/1999StickersPackEchoesArchimedeaFixed",
"ItemPrices": [
{
"ItemCount": 1,
"ItemType": "/Lotus/Types/Items/MiscItems/1999FixedStickersPack",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67db32b983b2ad79a9c1c18e"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/SyndicateVosforPack",
"ItemPrices": [
{
"ItemCount": 6,
"ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67db32b983b2ad79a9c1c18f"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/StickerPictureFrame",
"ItemPrices": [
{
"ItemCount": 10,
"ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67db32b983b2ad79a9c1c190"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/CosmeticEnhancers/Utility/AbilityRadiationProcsCreateUniversalOrbsOnKill",
"ItemPrices": [
{
"ItemCount": 5,
"ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "67db32b983b2ad79a9c1c191"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/CosmeticEnhancers/Offensive/AbilityHeatProcsGiveCritChance",
"ItemPrices": [
{
"ItemCount": 5,
"ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "67db32b983b2ad79a9c1c192"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/CosmeticEnhancers/Defensive/InvulnerabilityOnDeathOnMercyKill",
"ItemPrices": [
{
"ItemCount": 5,
"ItemType": "/Lotus/Types/Items/MiscItems/1999ConquestBucks",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"AllowMultipurchase": false,
"Id": {
"$oid": "67db32b983b2ad79a9c1c193"
}
}
],
"PropertyTextHash": "CB7D0E807FD5E2BCD059195201D963B9",
"RequiredGoalTag": "",
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
}
}
}

View File

@ -1,94 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5991d5e6bcc718474ee90c15"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Ostron/PetVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/LisetPropOstBirdCage",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Gems/Eidolon/UncommonOreAAlloyAItem",
"ItemCount": 10,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/DayUncommonFishBPartItem",
"ItemCount": 8,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9a8e"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/KubrowColorPackDrahk",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/DayCommonFishBPartItem",
"ItemCount": 14,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/BothCommonFishBPartItem",
"ItemCount": 13,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9a8f"
}
},
{
"StoreItem": "/Lotus/Types/StoreItems/Packages/KubrowColorPackFeral",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Fish/Eidolon/FishParts/BothCommonFishAPartItem",
"ItemCount": 19,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Gems/Eidolon/CommonOreBAlloyBItem",
"ItemCount": 34,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9a90"
}
}
],
"PropertyTextHash": "3D85F1A0A2B62734AE90370DEC214C26",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,126 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "5be4a159b144f3cdf1c22edf"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Solaris/DebtTokenVendorRepossessionsManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Venus/SUToolBox",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Solaris/DebtTokenB",
"ItemCount": 6,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6711a412ba1ba01e405e739d"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Venus/SUBookAOpen",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Solaris/DebtTokenC",
"ItemCount": 6,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6711a412ba1ba01e405e739e"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Venus/SUFoodCans",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Solaris/DebtTokenC",
"ItemCount": 7,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6711a412ba1ba01e405e739f"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Venus/SUTechToolD",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Solaris/DebtTokenD",
"ItemCount": 5,
"ProductCategory": "MiscItems"
},
{
"ItemType": "/Lotus/Types/Items/Solaris/DebtTokenA",
"ItemCount": 15,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_1",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6711a412ba1ba01e405e73a0"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Venus/SUContainerCrate",
"ItemPrices": [
{
"ItemType": "/Lotus/Types/Items/Solaris/DebtTokenA",
"ItemCount": 9,
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "6711a412ba1ba01e405e73a1"
}
}
],
"PropertyTextHash": "E0E83157D73468DC578403CB9EBA9DA6",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -1,459 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "67dadc30e4b6e0e5979c8d56"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/TheHex/Temple1999VendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TempleBlueprint",
"ItemPrices": [
{
"ItemCount": 195,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c18c"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TempleSystemsBlueprint",
"ItemPrices": [
{
"ItemCount": 65,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c18d"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TempleChassisBlueprint",
"ItemPrices": [
{
"ItemCount": 65,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c18e"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/WarframeRecipes/TempleHelmetBlueprint",
"ItemPrices": [
{
"ItemCount": 65,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c18f"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/1999EntHybridPistolBlueprint",
"ItemPrices": [
{
"ItemCount": 120,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c190"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/WeaponParts/1999EntHybridPistolBarrelBlueprint",
"ItemPrices": [
{
"ItemCount": 60,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c191"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/WeaponParts/1999EntHybridPistolReceiverBlueprint",
"ItemPrices": [
{
"ItemCount": 60,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c192"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Weapons/WeaponParts/1999EntHybridPistolStockBlueprint",
"ItemPrices": [
{
"ItemCount": 60,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c193"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumDrumCoreKitA",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c194"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumDrumCymbalA",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c195"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumDrumFloorTomA",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c196"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumDrumSnareA",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c197"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseA",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c198"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseB",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c199"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseC",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c19a"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseD",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c19b"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseE",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c19c"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumEquipmentCaseF",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c19d"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/Hollvania/LASxStadiumSynthKeyboardA",
"ItemPrices": [
{
"ItemCount": 30,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c19e"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/PhotoBooth/Vania/PhotoboothTileVaniaObjTempleDefense",
"ItemPrices": [
{
"ItemCount": 100,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": false,
"Id": {
"$oid": "67dadc30641da66dc5c1c19f"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
"ItemPrices": [
{
"ItemCount": 110,
"ItemType": "/Lotus/Types/Gameplay/1999Wf/Resources/1999ResourceDefense",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 6000,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 7,
"AllowMultipurchase": true,
"Id": {
"$oid": "67dadc30641da66dc5c1c1a5"
}
}
],
"PropertyTextHash": "20B13D9EB78FEC80EA32D0687F5BA1AE",
"RequiredGoalTag": "",
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
}
}
}

View File

@ -1,603 +0,0 @@
{
"VendorInfo": {
"_id": {
"$oid": "63ed01efbdaa38891767bac9"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Hubs/TeshinHardModeVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/OperatorArmour/HardMode/OperatorTeshinArmsBlueprint",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9947"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/OperatorArmour/HardMode/OperatorTeshinBodyBlueprint",
"ItemPrices": [
{
"ItemCount": 25,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9948"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/OperatorArmour/HardMode/OperatorTeshinHeadBlueprint",
"ItemPrices": [
{
"ItemCount": 20,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9949"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/OperatorArmour/HardMode/OperatorTeshinLegsBlueprint",
"ItemPrices": [
{
"ItemCount": 25,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e994a"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e994b"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e994c"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Components/FormaStanceBlueprint",
"ItemPrices": [
{
"ItemCount": 10,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e994d"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Skins/Effects/OrbsEphemera",
"ItemPrices": [
{
"ItemCount": 3,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e994e"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Skins/Effects/TatsuSkullEphemera",
"ItemPrices": [
{
"ItemCount": 85,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e994f"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Randomized/RawShotgunRandomMod",
"ItemPrices": [
{
"ItemCount": 75,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e9950"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Recipes/Components/UmbraFormaBlueprint",
"ItemPrices": [
{
"ItemCount": 150,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e9951"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
"ItemPrices": [
{
"ItemCount": 55,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 50000,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e9952"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Randomized/RawModularPistolRandomMod",
"ItemPrices": [
{
"ItemCount": 75,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e9953"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Forma",
"ItemPrices": [
{
"ItemCount": 75,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 3,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e9954"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Randomized/RawModularMeleeRandomMod",
"ItemPrices": [
{
"ItemCount": 75,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e9955"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/EvergreenLoginRewardFusionBundle",
"ItemPrices": [
{
"ItemCount": 150,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e9956"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Randomized/RawRifleRandomMod",
"ItemPrices": [
{
"ItemCount": 75,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e9957"
}
},
{
"StoreItem": "/Lotus/StoreItems/Upgrades/Mods/Shotgun/WeaponRecoilReductionMod",
"ItemPrices": [
{
"ItemCount": 35,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9958"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/TeshinBobbleHead",
"ItemPrices": [
{
"ItemCount": 35,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9959"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/StoreItems/AvatarImages/ImageGaussVED",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e995a"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/StoreItems/AvatarImages/ImageGrendelVED",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e995b"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageProteaAction",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e995c"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/TeaSet",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e995d"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/StoreItems/AvatarImages/AvatarImageXakuAction",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e995e"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/RivenIdentifier",
"ItemPrices": [
{
"ItemCount": 20,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "2051240400000"
}
},
"PurchaseQuantityLimit": 1,
"RotatedWeekly": true,
"AllowMultipurchase": false,
"Id": {
"$oid": "66fd60b20ba592c4c95e995f"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/RandomSyndicateProjectionPack",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 1,
"Expiry": {
"$date": {
"$numberLong": "604800000"
}
},
"PurchaseQuantityLimit": 25,
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e997c"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
"ItemPrices": [
{
"ItemCount": 15,
"ItemType": "/Lotus/Types/Items/MiscItems/SteelEssence",
"ProductCategory": "MiscItems"
}
],
"Bin": "BIN_0",
"QuantityMultiplier": 10000,
"Expiry": {
"$date": {
"$numberLong": "604800000"
}
},
"PurchaseQuantityLimit": 25,
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e997d"
}
}
],
"PropertyTextHash": "0A0F20AFA748FBEE490510DBF5A33A0D",
"Expiry": {
"$date": {
"$numberLong": "604800000"
}
}
}
}

View File

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

View File

@ -0,0 +1,154 @@
{
"VoidT1": [
"SolNode23",
"SolNode66",
"SolNode45",
"SolNode41",
"SolNode59",
"SolNode39",
"SolNode75",
"SolNode113",
"SolNode85",
"SolNode58",
"SolNode101",
"SolNode109",
"SolNode26",
"SolNode15",
"SolNode61",
"SolNode123",
"SolNode16",
"SolNode79",
"SolNode2",
"SolNode22",
"SolNode68",
"SolNode89",
"SolNode11",
"SolNode46",
"SolNode36",
"SolNode27",
"SolNode14",
"SolNode106",
"SolNode30",
"SolNode107",
"SolNode63",
"SolNode128"
],
"VoidT2": [
"SolNode141",
"SolNode149",
"SolNode10",
"SolNode93",
"SettlementNode11",
"SolNode137",
"SolNode132",
"SolNode73",
"SolNode82",
"SolNode25",
"SolNode88",
"SolNode126",
"SolNode135",
"SolNode74",
"SettlementNode15",
"SolNode147",
"SolNode67",
"SolNode20",
"SolNode42",
"SolNode18",
"SolNode31",
"SolNode139",
"SettlementNode12",
"SolNode100",
"SolNode140",
"SolNode70",
"SettlementNode1",
"SettlementNode14",
"SolNode50",
"SettlementNode2",
"SolNode146",
"SettlementNode3",
"SolNode97",
"SolNode125",
"SolNode19",
"SolNode121",
"SolNode96",
"SolNode131"
],
"VoidT3": [
"SolNode62",
"SolNode17",
"SolNode403",
"SolNode6",
"SolNode118",
"SolNode211",
"SolNode217",
"SolNode401",
"SolNode64",
"SolNode405",
"SolNode84",
"SolNode402",
"SolNode408",
"SolNode122",
"SolNode57",
"SolNode216",
"SolNode205",
"SolNode215",
"SolNode404",
"SolNode209",
"SolNode406",
"SolNode204",
"SolNode203",
"SolNode409",
"SolNode400",
"SolNode212",
"SolNode1",
"SolNode412",
"SolNode49",
"SolNode78",
"SolNode410",
"SolNode407",
"SolNode220"
],
"VoidT4": [
"SolNode188",
"SolNode403",
"SolNode189",
"SolNode21",
"SolNode102",
"SolNode171",
"SolNode196",
"SolNode184",
"SolNode185",
"SolNode76",
"SolNode195",
"SolNode164",
"SolNode401",
"SolNode405",
"SolNode56",
"SolNode402",
"SolNode408",
"SolNode4",
"SolNode181",
"SolNode406",
"SolNode162",
"SolNode72",
"SolNode407",
"SolNode177",
"SolNode404",
"SolNode400",
"SolNode409",
"SolNode43",
"SolNode166",
"SolNode172",
"SolNode412",
"SolNode187",
"SolNode38",
"SolNode175",
"SolNode81",
"SolNode48",
"SolNode410",
"SolNode153",
"SolNode173"
],
"VoidT5": ["SolNode747", "SolNode743", "SolNode742", "SolNode744", "SolNode745", "SolNode748", "SolNode746", "SolNode741"],
"VoidT6": ["SolNode717", "SolNode309", "SolNode718", "SolNode232", "SolNode230", "SolNode310"]
}

View File

@ -327,195 +327,6 @@
"Nodes": [] "Nodes": []
} }
], ],
"ActiveMissions": [
{
"_id": { "$oid": "663a7509d93367863785932d" },
"Region": 15,
"Seed": 80795,
"Activation": { "$date": { "$numberLong": "1715107081517" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode400",
"MissionType": "MT_EXTERMINATION",
"Modifier": "VoidT3",
"Hard": true
},
{
"_id": { "$oid": "663a75f959a5964cadb39879" },
"Region": 19,
"Seed": 32067,
"Activation": { "$date": { "$numberLong": "1715107321237" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode747",
"MissionType": "MT_INTEL",
"Modifier": "VoidT5",
"Hard": true
},
{
"_id": { "$oid": "663a779d3e347839ff301814" },
"Region": 7,
"Seed": 51739,
"Activation": { "$date": { "$numberLong": "1715107741454" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode64",
"MissionType": "MT_TERRITORY",
"Modifier": "VoidT3"
},
{
"_id": { "$oid": "663a77d916c199f4644ee67d" },
"Region": 17,
"Seed": 61179,
"Activation": { "$date": { "$numberLong": "1715107801647" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode718",
"MissionType": "MT_ALCHEMY",
"Modifier": "VoidT6"
},
{
"_id": { "$oid": "663a78c98a609b49b8410726" },
"Region": 3,
"Seed": 9520,
"Activation": { "$date": { "$numberLong": "1715108041501" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode79",
"MissionType": "MT_INTEL",
"Modifier": "VoidT1",
"Hard": true
},
{
"_id": { "$oid": "663a7df15eeabaac79b0a061" },
"Region": 6,
"Seed": 48861,
"Activation": { "$date": { "$numberLong": "1715109361974" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode67",
"MissionType": "MT_INTEL",
"Modifier": "VoidT2",
"Hard": true
},
{
"_id": { "$oid": "663a7df25eeabaac79b0a062" },
"Region": 5,
"Seed": 13550,
"Activation": { "$date": { "$numberLong": "1715109361974" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode10",
"MissionType": "MT_SABOTAGE",
"Modifier": "VoidT2",
"Hard": true
},
{
"_id": { "$oid": "663a83cdec0d5181435f1324" },
"Region": 19,
"Seed": 39392,
"Activation": { "$date": { "$numberLong": "1715110861506" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode742",
"MissionType": "MT_DEFENSE",
"Modifier": "VoidT5"
},
{
"_id": { "$oid": "663a83cdec0d5181435f1325" },
"Region": 19,
"Seed": 88668,
"Activation": { "$date": { "$numberLong": "1715110861506" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode743",
"MissionType": "MT_MOBILE_DEFENSE",
"Modifier": "VoidT5"
},
{
"_id": { "$oid": "663a83cdec0d5181435f1326" },
"Region": 19,
"Seed": 73823,
"Activation": { "$date": { "$numberLong": "1715110861506" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode741",
"MissionType": "MT_ASSAULT",
"Modifier": "VoidT5"
},
{
"_id": { "$oid": "663a878d23d1514873170466" },
"Region": 9,
"Seed": 88696,
"Activation": { "$date": { "$numberLong": "1715111821951" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode4",
"MissionType": "MT_EXTERMINATION",
"Modifier": "VoidT4",
"Hard": true
},
{
"_id": { "$oid": "663a887d4903098c10992fe6" },
"Region": 6,
"Seed": 66337,
"Activation": { "$date": { "$numberLong": "1715112061729" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode18",
"MissionType": "MT_TERRITORY",
"Modifier": "VoidT2"
},
{
"_id": { "$oid": "663a887d4903098c10992fe7" },
"Region": 10,
"Seed": 5135,
"Activation": { "$date": { "$numberLong": "1715112061729" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode149",
"MissionType": "MT_DEFENSE",
"Modifier": "VoidT2"
},
{
"_id": { "$oid": "663a8931586c301b1fbe63d3" },
"Region": 15,
"Seed": 32180,
"Activation": { "$date": { "$numberLong": "1715112241196" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode408",
"MissionType": "MT_DEFENSE",
"Modifier": "VoidT4"
},
{
"_id": { "$oid": "663a8931586c301b1fbe63d4" },
"Region": 12,
"Seed": 22521,
"Activation": { "$date": { "$numberLong": "1715112241196" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode181",
"MissionType": "MT_EXTERMINATION",
"Modifier": "VoidT4"
},
{
"_id": { "$oid": "663a8931586c301b1fbe63d5" },
"Region": 2,
"Seed": 28500,
"Activation": { "$date": { "$numberLong": "1715112241196" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode128",
"MissionType": "MT_EXTERMINATION",
"Modifier": "VoidT1"
},
{
"_id": { "$oid": "663a8931586c301b1fbe63d6" },
"Region": 3,
"Seed": 24747,
"Activation": { "$date": { "$numberLong": "1715112241196" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode26",
"MissionType": "MT_DEFENSE",
"Modifier": "VoidT1"
},
{
"_id": { "$oid": "663a8931586c301b1fbe63d7" },
"Region": 17,
"Seed": 63914,
"Activation": { "$date": { "$numberLong": "1715112241196" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"Node": "SolNode717",
"MissionType": "MT_SURVIVAL",
"Modifier": "VoidT6",
"Hard": true
}
],
"NodeOverrides": [ "NodeOverrides": [
{ "_id": { "$oid": "549b18e9b029cef5991d6aec" }, "Node": "EuropaHUB", "Hide": true }, { "_id": { "$oid": "549b18e9b029cef5991d6aec" }, "Node": "EuropaHUB", "Hide": true },
{ "_id": { "$oid": "54a1737aeb658f6cbccf70ff" }, "Node": "ErisHUB", "Hide": true }, { "_id": { "$oid": "54a1737aeb658f6cbccf70ff" }, "Node": "ErisHUB", "Hide": true },
@ -2562,50 +2373,6 @@
] ]
} }
], ],
"VoidStorms": [
{
"_id": { "$oid": "663a7581ced28e18f694b550" },
"Node": "CrewBattleNode519",
"Activation": { "$date": { "$numberLong": "1715109601821" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"ActiveMissionTier": "VoidT1"
},
{
"_id": { "$oid": "663a7581ced28e18f694b551" },
"Node": "CrewBattleNode515",
"Activation": { "$date": { "$numberLong": "1715109601825" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"ActiveMissionTier": "VoidT1"
},
{
"_id": { "$oid": "663a7581ced28e18f694b554" },
"Node": "CrewBattleNode536",
"Activation": { "$date": { "$numberLong": "1715109601832" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"ActiveMissionTier": "VoidT4"
},
{
"_id": { "$oid": "663a7581ced28e18f694b555" },
"Node": "CrewBattleNode539",
"Activation": { "$date": { "$numberLong": "1715109601834" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"ActiveMissionTier": "VoidT4"
},
{
"_id": { "$oid": "663a7581ced28e18f694b553" },
"Node": "CrewBattleNode521",
"Activation": { "$date": { "$numberLong": "1715109601829" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"ActiveMissionTier": "VoidT3"
},
{
"_id": { "$oid": "663a7581ced28e18f694b552" },
"Node": "CrewBattleNode535",
"Activation": { "$date": { "$numberLong": "1715109601827" } },
"Expiry": { "$date": { "$numberLong": "2000000000000" } },
"ActiveMissionTier": "VoidT2"
}
],
"PrimeAccessAvailability": { "State": "PRIME1" }, "PrimeAccessAvailability": { "State": "PRIME1" },
"PrimeVaultAvailabilities": [false, false, false, false, false], "PrimeVaultAvailabilities": [false, false, false, false, false],
"PrimeTokenAvailability": true, "PrimeTokenAvailability": true,

View File

@ -37,7 +37,7 @@
<li class="nav-item dropdown user-dropdown"> <li class="nav-item dropdown user-dropdown">
<button class="nav-link dropdown-toggle displayname" data-bs-toggle="dropdown" aria-expanded="false"></button> <button class="nav-link dropdown-toggle displayname" data-bs-toggle="dropdown" aria-expanded="false"></button>
<ul class="dropdown-menu dropdown-menu-end"> <ul class="dropdown-menu dropdown-menu-end">
<li><a class="dropdown-item" href="/webui/" onclick="logout();" data-loc="navbar_logout"></a></li> <li><a class="dropdown-item" href="/webui/" onclick="doLogout();" data-loc="navbar_logout"></a></li>
<li><hr class="dropdown-divider"></li> <li><hr class="dropdown-divider"></li>
<li><a class="dropdown-item" href="#" onclick="event.preventDefault();renameAccount();" data-loc="navbar_renameAccount"></a></li> <li><a class="dropdown-item" href="#" onclick="event.preventDefault();renameAccount();" data-loc="navbar_renameAccount"></a></li>
<li><a class="dropdown-item" href="#" onclick="event.preventDefault();deleteAccount();" data-loc="navbar_deleteAccount"></a></li> <li><a class="dropdown-item" href="#" onclick="event.preventDefault();deleteAccount();" data-loc="navbar_deleteAccount"></a></li>
@ -452,6 +452,9 @@
<button class="btn btn-success" onclick="maxRankAllEquipment(['SentinelWeapons']);" data-loc="inventory_bulkRankUpSentinelWeapons"></button> <button class="btn btn-success" onclick="maxRankAllEquipment(['SentinelWeapons']);" data-loc="inventory_bulkRankUpSentinelWeapons"></button>
<button class="btn btn-success" onclick="maxRankAllEvolutions();" data-loc="inventory_bulkRankUpEvolutionProgress"></button> <button class="btn btn-success" onclick="maxRankAllEvolutions();" data-loc="inventory_bulkRankUpEvolutionProgress"></button>
</div> </div>
<div class="mb-2 d-flex flex-wrap gap-2">
<button class="btn btn-primary" onclick="debounce(doMaxPlexus);" data-loc="inventory_maxPlexus"></button>
</div>
</div> </div>
</div> </div>
</div> </div>
@ -571,7 +574,7 @@
<div id="server-settings-no-perms" class="d-none"> <div id="server-settings-no-perms" class="d-none">
<p class="card-text" data-loc="cheats_administratorRequirement"></p> <p class="card-text" data-loc="cheats_administratorRequirement"></p>
</div> </div>
<form id="server-settings" class="d-none" onsubmit="doChangeSettings();return false;"> <div id="server-settings" class="d-none">
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="skipTutorial" /> <input class="form-check-input" type="checkbox" id="skipTutorial" />
<label class="form-check-label" for="skipTutorial" data-loc="cheats_skipTutorial"></label> <label class="form-check-label" for="skipTutorial" data-loc="cheats_skipTutorial"></label>
@ -604,13 +607,29 @@
<input class="form-check-input" type="checkbox" id="infiniteRegalAya" /> <input class="form-check-input" type="checkbox" id="infiniteRegalAya" />
<label class="form-check-label" for="infiniteRegalAya" data-loc="cheats_infiniteRegalAya"></label> <label class="form-check-label" for="infiniteRegalAya" data-loc="cheats_infiniteRegalAya"></label>
</div> </div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="infiniteHelminthMaterials" />
<label class="form-check-label" for="infiniteHelminthMaterials" data-loc="cheats_infiniteHelminthMaterials"></label>
</div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="claimingBlueprintRefundsIngredients" /> <input class="form-check-input" type="checkbox" id="claimingBlueprintRefundsIngredients" />
<label class="form-check-label" for="claimingBlueprintRefundsIngredients" data-loc="cheats_claimingBlueprintRefundsIngredients"></label> <label class="form-check-label" for="claimingBlueprintRefundsIngredients" data-loc="cheats_claimingBlueprintRefundsIngredients"></label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="infiniteHelminthMaterials" /> <input class="form-check-input" type="checkbox" id="dontSubtractPurchaseCreditCost" />
<label class="form-check-label" for="infiniteHelminthMaterials" data-loc="cheats_infiniteHelminthMaterials"></label> <label class="form-check-label" for="dontSubtractPurchaseCreditCost" data-loc="cheats_dontSubtractPurchaseCreditCost"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="dontSubtractPurchasePlatinumCost" />
<label class="form-check-label" for="dontSubtractPurchasePlatinumCost" data-loc="cheats_dontSubtractPurchasePlatinumCost"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="dontSubtractPurchaseItemCost" />
<label class="form-check-label" for="dontSubtractPurchaseItemCost" data-loc="cheats_dontSubtractPurchaseItemCost"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="dontSubtractPurchaseStandingCost" />
<label class="form-check-label" for="dontSubtractPurchaseStandingCost" data-loc="cheats_dontSubtractPurchaseStandingCost"></label>
</div> </div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="dontSubtractVoidTraces" /> <input class="form-check-input" type="checkbox" id="dontSubtractVoidTraces" />
@ -692,6 +711,10 @@
<input class="form-check-input" type="checkbox" id="syndicateMissionsRepeatable" /> <input class="form-check-input" type="checkbox" id="syndicateMissionsRepeatable" />
<label class="form-check-label" for="syndicateMissionsRepeatable" data-loc="cheats_syndicateMissionsRepeatable"></label> <label class="form-check-label" for="syndicateMissionsRepeatable" data-loc="cheats_syndicateMissionsRepeatable"></label>
</div> </div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="unlockAllProfitTakerStages" />
<label class="form-check-label" for="unlockAllProfitTakerStages" data-loc="cheats_unlockAllProfitTakerStages"></label>
</div>
<div class="form-check"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="instantFinishRivenChallenge" /> <input class="form-check-input" type="checkbox" id="instantFinishRivenChallenge" />
<label class="form-check-label" for="instantFinishRivenChallenge" data-loc="cheats_instantFinishRivenChallenge"></label> <label class="form-check-label" for="instantFinishRivenChallenge" data-loc="cheats_instantFinishRivenChallenge"></label>
@ -732,16 +755,25 @@
<input class="form-check-input" type="checkbox" id="fastClanAscension" /> <input class="form-check-input" type="checkbox" id="fastClanAscension" />
<label class="form-check-label" for="fastClanAscension" data-loc="cheats_fastClanAscension"></label> <label class="form-check-label" for="fastClanAscension" data-loc="cheats_fastClanAscension"></label>
</div> </div>
<div class="form-group mt-2"> <div class="form-check">
<input class="form-check-input" type="checkbox" id="missionsCanGiveAllRelics" />
<label class="form-check-label" for="missionsCanGiveAllRelics" data-loc="cheats_missionsCanGiveAllRelics"></label>
</div>
<form class="form-group mt-2" onsubmit="doSaveConfig('spoofMasteryRank'); return false;">
<label class="form-label" for="spoofMasteryRank" data-loc="cheats_spoofMasteryRank"></label> <label class="form-label" for="spoofMasteryRank" data-loc="cheats_spoofMasteryRank"></label>
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" max="65535" /> <div class="input-group">
</div> <input class="form-control" id="spoofMasteryRank" type="number" min="-1" max="65535" />
<div class="form-group mt-2"> <button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
</div>
</form>
<form class="form-group mt-2" onsubmit="doSaveConfig('nightwaveStandingMultiplier'); return false;">
<label class="form-label" for="nightwaveStandingMultiplier" data-loc="cheats_nightwaveStandingMultiplier"></label> <label class="form-label" for="nightwaveStandingMultiplier" data-loc="cheats_nightwaveStandingMultiplier"></label>
<input class="form-control" id="nightwaveStandingMultiplier" type="number" min="1" max="1000000" value="1" /> <div class="input-group">
</div> <input class="form-control" id="nightwaveStandingMultiplier" type="number" min="1" max="1000000" value="1" />
<button class="btn btn-primary mt-3" type="submit" data-loc="cheats_saveSettings"></button> <button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
</form> </div>
</form>
</div>
</div> </div>
</div> </div>
</div> </div>

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long

View File

@ -1,21 +1,58 @@
let loginOrRegisterPending = false; /* eslint-disable @typescript-eslint/no-unsafe-return */
window.registerSubmit = false; /* eslint-disable @typescript-eslint/no-floating-promises */
/* eslint-disable @typescript-eslint/no-unused-vars */
/* eslint-disable @typescript-eslint/no-unsafe-argument */
/* eslint-disable no-undef */
/* eslint-disable @typescript-eslint/no-unsafe-call */
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
/* eslint-disable @typescript-eslint/no-unsafe-member-access */
/* eslint-disable @typescript-eslint/explicit-function-return-type */
function doLogin() { let auth_pending = false,
if (loginOrRegisterPending) { did_initial_auth = false,
return; ws_is_open = false;
const sendAuth = isRegister => {
if (ws_is_open && localStorage.getItem("email") && localStorage.getItem("password")) {
auth_pending = true;
window.ws.send(
JSON.stringify({
auth: {
email: localStorage.getItem("email"),
password: wp.encSync(localStorage.getItem("password")),
isRegister
}
})
);
} }
loginOrRegisterPending = true; };
localStorage.setItem("email", $("#email").val());
localStorage.setItem("password", $("#password").val());
loginFromLocalStorage();
registerSubmit = false;
}
function loginFromLocalStorage() { function openWebSocket() {
const isRegister = registerSubmit; window.ws = new WebSocket("/custom/ws");
doLoginRequest( window.ws.onopen = () => {
data => { ws_is_open = true;
sendAuth(false);
};
window.ws.onmessage = e => {
const msg = JSON.parse(e.data);
if ("reload" in msg) {
setTimeout(() => {
getWebSocket().then(() => {
location.reload();
});
}, 100);
}
if ("ports" in msg) {
location.port = location.protocol == "https:" ? msg.ports.https : msg.ports.http;
}
if ("config_reloaded" in msg) {
//window.is_admin = undefined;
if (single.getCurrentPath() == "/webui/cheats") {
single.loadRoute("/webui/cheats");
}
}
if ("auth_succ" in msg) {
auth_pending = false;
const data = msg.auth_succ;
if (single.getCurrentPath() == "/webui/") { if (single.getCurrentPath() == "/webui/") {
single.loadRoute("/webui/inventory"); single.loadRoute("/webui/inventory");
} }
@ -25,54 +62,74 @@ function loginFromLocalStorage() {
if (window.dict) { if (window.dict) {
updateLocElements(); updateLocElements();
} }
updateInventory(); if (!did_initial_auth) {
}, did_initial_auth = true;
() => { updateInventory();
logout(); }
alert(isRegister ? "Registration failed. Account already exists?" : "Login failed");
} }
); if ("auth_fail" in msg) {
auth_pending = false;
logout();
if (single.getCurrentPath() == "/webui/") {
alert(loc(msg.auth_fail.isRegister ? "code_regFail" : "code_loginFail"));
} else {
single.loadRoute("/webui/");
}
}
if ("logged_out" in msg) {
sendAuth();
}
};
window.ws.onclose = function () {
ws_is_open = false;
setTimeout(openWebSocket, 3000);
};
}
openWebSocket();
function getWebSocket() {
return new Promise(resolve => {
let interval;
interval = setInterval(() => {
if (ws_is_open) {
clearInterval(interval);
resolve(window.ws);
}
}, 10);
});
} }
function doLoginRequest(succ_cb, fail_cb) { window.registerSubmit = false;
const req = $.post({
url: "/api/login.php", function doLogin() {
contentType: "text/plain", if (auth_pending) {
data: JSON.stringify({ return;
email: localStorage.getItem("email").toLowerCase(), }
password: wp.encSync(localStorage.getItem("password"), "hex"), localStorage.setItem("email", $("#email").val());
time: parseInt(new Date() / 1000), localStorage.setItem("password", $("#password").val());
s: "W0RFXVN0ZXZlIGxpa2VzIGJpZyBidXR0cw==", // signature of some kind sendAuth(registerSubmit);
lang: "en", window.registerSubmit = false;
date: 1501230947855458660, // ???
ClientType: registerSubmit ? "webui-register" : "webui",
PS: "W0RFXVN0ZXZlIGxpa2VzIGJpZyBidXR0cw==" // anti-cheat data
})
});
req.done(succ_cb);
req.fail(fail_cb);
req.always(() => {
loginOrRegisterPending = false;
});
} }
function revalidateAuthz(succ_cb) { function revalidateAuthz(succ_cb) {
return doLoginRequest( getWebSocket().then(() => {
data => { // We have a websocket connection, so authz should be good.
window.authz = "accountId=" + data.id + "&nonce=" + data.Nonce; succ_cb();
succ_cb(); });
},
() => {
logout();
alert(loc("code_nonValidAuthz"));
single.loadRoute("/webui/"); // Show login screen
}
);
} }
function logout() { function logout() {
localStorage.removeItem("email"); localStorage.removeItem("email");
localStorage.removeItem("password"); localStorage.removeItem("password");
did_initial_auth = false;
}
function doLogout() {
logout();
if (ws_is_open) {
// Unsubscribe from notifications about nonce invalidation
window.ws.send(JSON.stringify({ logout: true }));
}
} }
function renameAccount() { function renameAccount() {
@ -98,10 +155,6 @@ function deleteAccount() {
} }
} }
if (localStorage.getItem("email") && localStorage.getItem("password")) {
loginFromLocalStorage();
}
single.on("route_load", function (event) { single.on("route_load", function (event) {
if (event.route.paths[0] != "/webui/") { if (event.route.paths[0] != "/webui/") {
// Authorised route? // Authorised route?
@ -546,6 +599,9 @@ function updateInventory() {
td.textContent = item.ItemName + " (" + td.textContent + ")"; td.textContent = item.ItemName + " (" + td.textContent + ")";
} }
} }
if (item.Details?.Name) {
td.textContent = item.Details.Name + " (" + td.textContent + ")";
}
if (item.ModularParts && item.ModularParts.length) { if (item.ModularParts && item.ModularParts.length) {
td.textContent += " ["; td.textContent += " [";
item.ModularParts.forEach(part => { item.ModularParts.forEach(part => {
@ -591,8 +647,9 @@ function updateInventory() {
a.onclick = function (event) { a.onclick = function (event) {
event.preventDefault(); event.preventDefault();
revalidateAuthz(() => { revalidateAuthz(() => {
const promises = [];
if (item.XP < maxXP) { if (item.XP < maxXP) {
addGearExp(category, item.ItemId.$oid, maxXP - item.XP); promises.push(addGearExp(category, item.ItemId.$oid, maxXP - item.XP));
} }
if ("exalted" in itemMap[item.ItemType]) { if ("exalted" in itemMap[item.ItemType]) {
for (const exaltedType of itemMap[item.ItemType].exalted) { for (const exaltedType of itemMap[item.ItemType].exalted) {
@ -601,15 +658,20 @@ function updateInventory() {
const exaltedCap = const exaltedCap =
itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
if (exaltedItem.XP < exaltedCap) { if (exaltedItem.XP < exaltedCap) {
addGearExp( promises.push(
"SpecialItems", addGearExp(
exaltedItem.ItemId.$oid, "SpecialItems",
exaltedCap - exaltedItem.XP exaltedItem.ItemId.$oid,
exaltedCap - exaltedItem.XP
)
); );
} }
} }
} }
} }
Promise.all(promises).then(() => {
updateInventory();
});
}); });
}; };
a.title = loc("code_maxRank"); a.title = loc("code_maxRank");
@ -758,6 +820,13 @@ function updateInventory() {
giveAllQEvolutionProgress.disabled = true; giveAllQEvolutionProgress.disabled = true;
} }
if (data.CrewShipHarnesses?.length) {
window.plexus = {
id: data.CrewShipHarnesses[0].ItemId.$oid,
xp: data.CrewShipHarnesses[0].XP
};
}
// Populate quests route // Populate quests route
document.getElementById("QuestKeys-list").innerHTML = ""; document.getElementById("QuestKeys-list").innerHTML = "";
data.QuestKeys.forEach(item => { data.QuestKeys.forEach(item => {
@ -1440,20 +1509,17 @@ function maxRankAllEquipment(categories) {
XP: maxXP XP: maxXP
}); });
} }
if (category === "Suits") { if (item.ItemType in itemMap && "exalted" in itemMap[item.ItemType]) {
if ("exalted" in itemMap[item.ItemType]) { for (const exaltedType of itemMap[item.ItemType].exalted) {
for (const exaltedType of itemMap[item.ItemType].exalted) { const exaltedItem = data["SpecialItems"].find(x => x.ItemType == exaltedType);
const exaltedItem = data["SpecialItems"].find(x => x.ItemType == exaltedType); if (exaltedItem) {
if (exaltedItem) { const exaltedCap = itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
const exaltedCap = if (exaltedItem.XP < exaltedCap) {
itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000; batchData["SpecialItems"] ??= [];
if (exaltedItem.XP < exaltedCap) { batchData["SpecialItems"].push({
batchData["SpecialItems"] ??= []; ItemId: { $oid: exaltedItem.ItemId.$oid },
batchData["SpecialItems"].push({ XP: exaltedCap
ItemId: { $oid: exaltedItem.ItemId.$oid }, });
XP: exaltedCap
});
}
} }
} }
} }
@ -1480,14 +1546,14 @@ function addGearExp(category, oid, xp) {
XP: xp XP: xp
} }
]; ];
$.post({ return new Promise((resolve, reject) => {
url: "/custom/addXp?" + window.authz, $.post({
contentType: "application/json", url: "/custom/addXp?" + window.authz,
data: JSON.stringify(data) contentType: "application/json",
}).done(function () { data: JSON.stringify(data)
if (category != "SpecialItems") { })
updateInventory(); .done(resolve)
} .fail(reject);
}); });
} }
@ -1506,15 +1572,28 @@ function sendBatchGearExp(data) {
function renameGear(category, oid, name) { function renameGear(category, oid, name) {
revalidateAuthz(() => { revalidateAuthz(() => {
$.post({ if (category == "KubrowPets") {
url: "/api/nameWeapon.php?" + window.authz + "&Category=" + category + "&ItemId=" + oid + "&webui=1", $.post({
contentType: "text/plain", url: "/api/renamePet.php?" + window.authz + "&webui=1",
data: JSON.stringify({ contentType: "text/plain",
ItemName: name data: JSON.stringify({
}) petId: oid,
}).done(function () { name: name
updateInventory(); })
}); }).done(function () {
updateInventory();
});
} else {
$.post({
url: "/api/nameWeapon.php?" + window.authz + "&Category=" + category + "&ItemId=" + oid + "&webui=1",
contentType: "text/plain",
data: JSON.stringify({
ItemName: name
})
}).done(function () {
updateInventory();
});
}
}); });
} }
@ -1651,7 +1730,9 @@ function doAcquireRiven() {
if (typeof fingerprint !== "object") { if (typeof fingerprint !== "object") {
fingerprint = JSON.parse(fingerprint); fingerprint = JSON.parse(fingerprint);
} }
} catch (e) {} } catch (e) {
/* empty */
}
if ( if (
typeof fingerprint !== "object" || typeof fingerprint !== "object" ||
!("compat" in fingerprint) || !("compat" in fingerprint) ||
@ -1761,34 +1842,29 @@ function doAcquireMod() {
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id); const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
function doChangeSettings() { for (const id of uiConfigs) {
revalidateAuthz(() => { const elm = document.getElementById(id);
fetch("/custom/config?" + window.authz) if (elm.type == "checkbox") {
.then(response => response.json()) elm.onchange = function () {
.then(json => { $.post({
for (const i of uiConfigs) { url: "/custom/config?" + window.authz,
var x = document.getElementById(i); contentType: "application/json",
if (x != null) { data: JSON.stringify({ key: id, value: this.checked })
if (x.type == "checkbox") { }).then(() => {
if (x.checked === true) { if (["infiniteCredits", "infinitePlatinum", "infiniteEndo", "infiniteRegalAya"].indexOf(id) != -1) {
json[i] = true;
} else {
json[i] = false;
}
} else if (x.type == "number") {
json[i] = parseInt(x.value);
}
}
}
$.post({
url: "/custom/config?" + window.authz,
contentType: "text/plain",
data: JSON.stringify(json, null, 2)
}).then(() => {
// A few cheats affect the inventory response which in turn may change what values we need to show
updateInventory(); updateInventory();
}); }
}); });
};
}
}
function doSaveConfig(id) {
const elm = document.getElementById(id);
$.post({
url: "/custom/config?" + window.authz,
contentType: "application/json",
data: JSON.stringify({ key: id, value: parseInt(elm.value) })
}); });
} }
@ -1801,6 +1877,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
clearInterval(interval); clearInterval(interval);
fetch("/custom/config?" + window.authz).then(async res => { fetch("/custom/config?" + window.authz).then(async res => {
if (res.status == 200) { if (res.status == 200) {
//window.is_admin = true;
$("#server-settings-no-perms").addClass("d-none"); $("#server-settings-no-perms").addClass("d-none");
$("#server-settings").removeClass("d-none"); $("#server-settings").removeClass("d-none");
res.json().then(json => res.json().then(json =>
@ -1809,9 +1886,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
var x = document.getElementById(`${key}`); var x = document.getElementById(`${key}`);
if (x != null) { if (x != null) {
if (x.type == "checkbox") { if (x.type == "checkbox") {
if (value === true) { x.checked = value;
x.setAttribute("checked", "checked");
}
} else if (x.type == "number") { } else if (x.type == "number") {
x.setAttribute("value", `${value}`); x.setAttribute("value", `${value}`);
} }
@ -1826,6 +1901,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
} }
}); });
} else { } else {
//window.is_admin = false;
$("#server-settings-no-perms").removeClass("d-none"); $("#server-settings-no-perms").removeClass("d-none");
$("#server-settings").addClass("d-none"); $("#server-settings").addClass("d-none");
} }
@ -1909,7 +1985,7 @@ function doAddAllMods() {
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1"); const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
req.done(data => { req.done(data => {
for (const modOwned of data.RawUpgrades) { for (const modOwned of data.RawUpgrades) {
if (modOwned.ItemCount ?? 1 > 0) { if ((modOwned.ItemCount ?? 1) > 0) {
modsAll.delete(modOwned.ItemType); modsAll.delete(modOwned.ItemType);
} }
} }
@ -2238,3 +2314,21 @@ function formatDatetime(fmt, date) {
} }
}); });
} }
const calls_in_flight = new Set();
async function debounce(func, ...args) {
calls_in_flight.add(func);
await func(...args);
calls_in_flight.delete(func);
}
async function doMaxPlexus() {
if ((window.plexus?.xp ?? 0) < 900_000) {
await addGearExp("CrewShipHarnesses", window.plexus.id, 900_000 - window.plexus.xp);
window.plexus.xp = 900_000;
toast(loc("code_succRankUp"));
} else {
toast(loc("code_noEquipmentToRankUp"));
}
}

View File

@ -3,7 +3,8 @@ dict = {
general_inventoryUpdateNote: `Hinweis: Änderungen, die hier vorgenommen werden, werden erst im Spiel angewendet, sobald das Inventar synchronisiert wird. Die Sternenkarte zu besuchen, sollte der einfachste Weg sein, dies auszulösen.`, general_inventoryUpdateNote: `Hinweis: Änderungen, die hier vorgenommen werden, werden erst im Spiel angewendet, sobald das Inventar synchronisiert wird. Die Sternenkarte zu besuchen, sollte der einfachste Weg sein, dies auszulösen.`,
general_addButton: `Hinzufügen`, general_addButton: `Hinzufügen`,
general_bulkActions: `Massenaktionen`, general_bulkActions: `Massenaktionen`,
code_nonValidAuthz: `Deine Anmeldedaten sind nicht mehr gültig.`, code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
code_changeNameConfirm: `In welchen Namen möchtest du deinen Account umbenennen?`, code_changeNameConfirm: `In welchen Namen möchtest du deinen Account umbenennen?`,
code_deleteAccountConfirm: `Bist du sicher, dass du deinen Account |DISPLAYNAME| (|EMAIL|) löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.`, code_deleteAccountConfirm: `Bist du sicher, dass du deinen Account |DISPLAYNAME| (|EMAIL|) löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.`,
code_archgun: `Arch-Gewehr`, code_archgun: `Arch-Gewehr`,
@ -84,6 +85,7 @@ dict = {
inventory_moaPets: `Moas`, inventory_moaPets: `Moas`,
inventory_kubrowPets: `Bestien`, inventory_kubrowPets: `Bestien`,
inventory_evolutionProgress: `Incarnon-Entwicklungsfortschritte`, inventory_evolutionProgress: `Incarnon-Entwicklungsfortschritte`,
inventory_Boosters: `[UNTRANSLATED] Boosters`,
inventory_bulkAddSuits: `Fehlende Warframes hinzufügen`, inventory_bulkAddSuits: `Fehlende Warframes hinzufügen`,
inventory_bulkAddWeapons: `Fehlende Waffen hinzufügen`, inventory_bulkAddWeapons: `Fehlende Waffen hinzufügen`,
inventory_bulkAddSpaceSuits: `Fehlende Archwings hinzufügen`, inventory_bulkAddSpaceSuits: `Fehlende Archwings hinzufügen`,
@ -98,7 +100,7 @@ dict = {
inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`, inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`, inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`, inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`,
inventory_Boosters: `[UNTRANSLATED] Boosters`, inventory_maxPlexus: `[UNTRANSLATED] Max Rank Plexus`,
quests_list: `Quests`, quests_list: `Quests`,
quests_completeAll: `Alle Quests abschließen`, quests_completeAll: `Alle Quests abschließen`,
@ -133,11 +135,15 @@ dict = {
cheats_infiniteRegalAya: `Unendlich Reines Aya`, cheats_infiniteRegalAya: `Unendlich Reines Aya`,
cheats_infiniteHelminthMaterials: `Unendlich Helminth-Materialien`, cheats_infiniteHelminthMaterials: `Unendlich Helminth-Materialien`,
cheats_claimingBlueprintRefundsIngredients: `Fertige Blaupausen erstatten Ressourcen zurück`, cheats_claimingBlueprintRefundsIngredients: `Fertige Blaupausen erstatten Ressourcen zurück`,
cheats_dontSubtractPurchaseCreditCost: `[UNTRANSLATED] Don't Subtract Purchase Credit Cost`,
cheats_dontSubtractPurchasePlatinumCost: `[UNTRANSLATED] Don't Subtract Purchase Platinum Cost`,
cheats_dontSubtractPurchaseItemCost: `[UNTRANSLATED] Don't Subtract Purchase Item Cost`,
cheats_dontSubtractPurchaseStandingCost: `[UNTRANSLATED] Don't Subtract Purchase Standing Cost`,
cheats_dontSubtractVoidTraces: `Void-Spuren nicht verbrauchen`, cheats_dontSubtractVoidTraces: `Void-Spuren nicht verbrauchen`,
cheats_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`, cheats_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`,
cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`, cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`,
cheats_unlockAllShipDecorations: `Alle Schiffsdekorationen freischalten`, cheats_unlockAllShipDecorations: `Alle Schiffsdekorationen freischalten`,
cheats_unlockAllFlavourItems: `Alle <abbr title=\"Animationssets, Glyphen, Farbpaletten usw.\">Sammlerstücke</abbr> freischalten`, cheats_unlockAllFlavourItems: `Alle <abbr title="Animationssets, Glyphen, Farbpaletten usw.">Sammlerstücke</abbr> freischalten`,
cheats_unlockAllSkins: `Alle Skins freischalten`, cheats_unlockAllSkins: `Alle Skins freischalten`,
cheats_unlockAllCapturaScenes: `Alle Photora-Szenen freischalten`, cheats_unlockAllCapturaScenes: `Alle Photora-Szenen freischalten`,
cheats_unlockAllDecoRecipes: `Alle Dojo-Deko-Baupläne freischalten`, cheats_unlockAllDecoRecipes: `Alle Dojo-Deko-Baupläne freischalten`,
@ -153,6 +159,7 @@ dict = {
cheats_noDeathMarks: `Keine Todesmarkierungen`, cheats_noDeathMarks: `Keine Todesmarkierungen`,
cheats_noKimCooldowns: `Keine Wartezeit bei KIM`, cheats_noKimCooldowns: `Keine Wartezeit bei KIM`,
cheats_syndicateMissionsRepeatable: `Syndikat-Missionen wiederholbar`, cheats_syndicateMissionsRepeatable: `Syndikat-Missionen wiederholbar`,
cheats_unlockAllProfitTakerStages: `[UNTRANSLATED] Unlock All Profit Taker Stages`,
cheats_instantFinishRivenChallenge: `Riven-Mod Herausforderung sofort abschließen`, cheats_instantFinishRivenChallenge: `Riven-Mod Herausforderung sofort abschließen`,
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`, cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`, cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,
@ -163,9 +170,10 @@ dict = {
cheats_noDojoResearchCosts: `Keine Dojo-Forschungskosten`, cheats_noDojoResearchCosts: `Keine Dojo-Forschungskosten`,
cheats_noDojoResearchTime: `Keine Dojo-Forschungszeit`, cheats_noDojoResearchTime: `Keine Dojo-Forschungszeit`,
cheats_fastClanAscension: `Schneller Clan-Aufstieg`, cheats_fastClanAscension: `Schneller Clan-Aufstieg`,
cheats_missionsCanGiveAllRelics: `[UNTRANSLATED] Missions Can Give All Relics`,
cheats_spoofMasteryRank: `Gefälschter Meisterschaftsrang (-1 zum deaktivieren)`, cheats_spoofMasteryRank: `Gefälschter Meisterschaftsrang (-1 zum deaktivieren)`,
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`, cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
cheats_saveSettings: `Einstellungen speichern`, cheats_save: `[UNTRANSLATED] Save`,
cheats_account: `Account`, cheats_account: `Account`,
cheats_unlockAllFocusSchools: `Alle Fokus-Schulen freischalten`, cheats_unlockAllFocusSchools: `Alle Fokus-Schulen freischalten`,
cheats_helminthUnlockAll: `Helminth vollständig aufleveln`, cheats_helminthUnlockAll: `Helminth vollständig aufleveln`,
@ -183,7 +191,7 @@ dict = {
upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`, upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`,
upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`, upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`,
upgrade_WarframeArmourMax: `[UNTRANSLATED] +|VAL| Armor`, upgrade_WarframeArmourMax: `[UNTRANSLATED] +|VAL| Armor`,
upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on inflicting Blast Status`, upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on kill with Blast Damage`,
upgrade_WarframeCastingSpeed: `[UNTRANSLATED] +|VAL|% Casting Speed`, upgrade_WarframeCastingSpeed: `[UNTRANSLATED] +|VAL|% Casting Speed`,
upgrade_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`, upgrade_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`,
upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`, upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`,

View File

@ -2,7 +2,8 @@ dict = {
general_inventoryUpdateNote: `Note: Changes made here will only be applied in-game when the game syncs the inventory. Visiting the navigation should be the easiest way to trigger that.`, general_inventoryUpdateNote: `Note: Changes made here will only be applied in-game when the game syncs the inventory. Visiting the navigation should be the easiest way to trigger that.`,
general_addButton: `Add`, general_addButton: `Add`,
general_bulkActions: `Bulk Actions`, general_bulkActions: `Bulk Actions`,
code_nonValidAuthz: `Your credentials are no longer valid.`, code_loginFail: `Login failed. Double-check the email and password.`,
code_regFail: `Registration failed. Account already exists?`,
code_changeNameConfirm: `What would you like to change your account name to?`, code_changeNameConfirm: `What would you like to change your account name to?`,
code_deleteAccountConfirm: `Are you sure you want to delete your account |DISPLAYNAME| (|EMAIL|)? This action cannot be undone.`, code_deleteAccountConfirm: `Are you sure you want to delete your account |DISPLAYNAME| (|EMAIL|)? This action cannot be undone.`,
code_archgun: `Archgun`, code_archgun: `Archgun`,
@ -83,6 +84,7 @@ dict = {
inventory_moaPets: `Moas`, inventory_moaPets: `Moas`,
inventory_kubrowPets: `Beasts`, inventory_kubrowPets: `Beasts`,
inventory_evolutionProgress: `Incarnon Evolution Progress`, inventory_evolutionProgress: `Incarnon Evolution Progress`,
inventory_Boosters: `Boosters`,
inventory_bulkAddSuits: `Add Missing Warframes`, inventory_bulkAddSuits: `Add Missing Warframes`,
inventory_bulkAddWeapons: `Add Missing Weapons`, inventory_bulkAddWeapons: `Add Missing Weapons`,
inventory_bulkAddSpaceSuits: `Add Missing Archwings`, inventory_bulkAddSpaceSuits: `Add Missing Archwings`,
@ -97,7 +99,7 @@ dict = {
inventory_bulkRankUpSentinels: `Max Rank All Sentinels`, inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`, inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
inventory_bulkRankUpEvolutionProgress: `Max Rank All Incarnon Evolution Progress`, inventory_bulkRankUpEvolutionProgress: `Max Rank All Incarnon Evolution Progress`,
inventory_Boosters: `Boosters`, inventory_maxPlexus: `Max Rank Plexus`,
quests_list: `Quests`, quests_list: `Quests`,
quests_completeAll: `Complete All Quests`, quests_completeAll: `Complete All Quests`,
@ -132,11 +134,15 @@ dict = {
cheats_infiniteRegalAya: `Infinite Regal Aya`, cheats_infiniteRegalAya: `Infinite Regal Aya`,
cheats_infiniteHelminthMaterials: `Infinite Helminth Materials`, cheats_infiniteHelminthMaterials: `Infinite Helminth Materials`,
cheats_claimingBlueprintRefundsIngredients: `Claiming Blueprint Refunds Ingredients`, cheats_claimingBlueprintRefundsIngredients: `Claiming Blueprint Refunds Ingredients`,
cheats_dontSubtractPurchaseCreditCost: `Don't Subtract Purchase Credit Cost`,
cheats_dontSubtractPurchasePlatinumCost: `Don't Subtract Purchase Platinum Cost`,
cheats_dontSubtractPurchaseItemCost: `Don't Subtract Purchase Item Cost`,
cheats_dontSubtractPurchaseStandingCost: `Don't Subtract Purchase Standing Cost`,
cheats_dontSubtractVoidTraces: `Don't Subtract Void Traces`, cheats_dontSubtractVoidTraces: `Don't Subtract Void Traces`,
cheats_dontSubtractConsumables: `Don't Subtract Consumables`, cheats_dontSubtractConsumables: `Don't Subtract Consumables`,
cheats_unlockAllShipFeatures: `Unlock All Ship Features`, cheats_unlockAllShipFeatures: `Unlock All Ship Features`,
cheats_unlockAllShipDecorations: `Unlock All Ship Decorations`, cheats_unlockAllShipDecorations: `Unlock All Ship Decorations`,
cheats_unlockAllFlavourItems: `Unlock All <abbr title=\"Animation Sets, Glyphs, Palettes, etc.\">Flavor Items</abbr>`, cheats_unlockAllFlavourItems: `Unlock All <abbr title="Animation Sets, Glyphs, Palettes, etc.">Flavor Items</abbr>`,
cheats_unlockAllSkins: `Unlock All Skins`, cheats_unlockAllSkins: `Unlock All Skins`,
cheats_unlockAllCapturaScenes: `Unlock All Captura Scenes`, cheats_unlockAllCapturaScenes: `Unlock All Captura Scenes`,
cheats_unlockAllDecoRecipes: `Unlock All Dojo Deco Recipes`, cheats_unlockAllDecoRecipes: `Unlock All Dojo Deco Recipes`,
@ -152,6 +158,7 @@ dict = {
cheats_noDeathMarks: `No Death Marks`, cheats_noDeathMarks: `No Death Marks`,
cheats_noKimCooldowns: `No KIM Cooldowns`, cheats_noKimCooldowns: `No KIM Cooldowns`,
cheats_syndicateMissionsRepeatable: `Syndicate Missions Repeatable`, cheats_syndicateMissionsRepeatable: `Syndicate Missions Repeatable`,
cheats_unlockAllProfitTakerStages: `Unlock All Profit Taker Stages`,
cheats_instantFinishRivenChallenge: `Instant Finish Riven Challenge`, cheats_instantFinishRivenChallenge: `Instant Finish Riven Challenge`,
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`, cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
cheats_noResourceExtractorDronesDamage: `No Resource Extractor Drones Damage`, cheats_noResourceExtractorDronesDamage: `No Resource Extractor Drones Damage`,
@ -162,9 +169,10 @@ dict = {
cheats_noDojoResearchCosts: `No Dojo Research Costs`, cheats_noDojoResearchCosts: `No Dojo Research Costs`,
cheats_noDojoResearchTime: `No Dojo Research Time`, cheats_noDojoResearchTime: `No Dojo Research Time`,
cheats_fastClanAscension: `Fast Clan Ascension`, cheats_fastClanAscension: `Fast Clan Ascension`,
cheats_missionsCanGiveAllRelics: `Missions Can Give All Relics`,
cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`, cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`,
cheats_nightwaveStandingMultiplier: `Nightwave Standing Multiplier`, cheats_nightwaveStandingMultiplier: `Nightwave Standing Multiplier`,
cheats_saveSettings: `Save Settings`, cheats_save: `Save`,
cheats_account: `Account`, cheats_account: `Account`,
cheats_unlockAllFocusSchools: `Unlock All Focus Schools`, cheats_unlockAllFocusSchools: `Unlock All Focus Schools`,
cheats_helminthUnlockAll: `Fully Level Up Helminth`, cheats_helminthUnlockAll: `Fully Level Up Helminth`,
@ -182,7 +190,7 @@ dict = {
upgrade_WarframeAbilityDuration: `+|VAL|% Ability Duration`, upgrade_WarframeAbilityDuration: `+|VAL|% Ability Duration`,
upgrade_WarframeAbilityStrength: `+|VAL|% Ability Strength`, upgrade_WarframeAbilityStrength: `+|VAL|% Ability Strength`,
upgrade_WarframeArmourMax: `+|VAL| Armor`, upgrade_WarframeArmourMax: `+|VAL| Armor`,
upgrade_WarframeBlastProc: `+|VAL| Shields on inflicting Blast Status`, upgrade_WarframeBlastProc: `+|VAL| Shields on kill with Blast Damage`,
upgrade_WarframeCastingSpeed: `+|VAL|% Casting Speed`, upgrade_WarframeCastingSpeed: `+|VAL|% Casting Speed`,
upgrade_WarframeCorrosiveDamageBoost: `+|VAL|% Ability Damage on enemies affected by Corrosion Status`, upgrade_WarframeCorrosiveDamageBoost: `+|VAL|% Ability Damage on enemies affected by Corrosion Status`,
upgrade_WarframeCorrosiveStack: `Increase max stacks of Corrosion Status by +|VAL|`, upgrade_WarframeCorrosiveStack: `Increase max stacks of Corrosion Status by +|VAL|`,

View File

@ -3,7 +3,8 @@ dict = {
general_inventoryUpdateNote: `Nota: Los cambios realizados aquí se reflejarán en el juego cuando este sincronice el inventario. Usar la navegación debería ser la forma más sencilla de activar esto.`, general_inventoryUpdateNote: `Nota: Los cambios realizados aquí se reflejarán en el juego cuando este sincronice el inventario. Usar la navegación debería ser la forma más sencilla de activar esto.`,
general_addButton: `Agregar`, general_addButton: `Agregar`,
general_bulkActions: `Acciones masivas`, general_bulkActions: `Acciones masivas`,
code_nonValidAuthz: `Tus credenciales no son válidas.`, code_loginFail: `Error al iniciar sesión. Verifica el correo electrónico y la contraseña.`,
code_regFail: `Error al registrar la cuenta. ¿Ya existe una cuenta con este correo?`,
code_changeNameConfirm: `¿Qué nombre te gustaría ponerle a tu cuenta?`, code_changeNameConfirm: `¿Qué nombre te gustaría ponerle a tu cuenta?`,
code_deleteAccountConfirm: `¿Estás seguro de que deseas eliminar tu cuenta |DISPLAYNAME| (|EMAIL|)? Esta acción es permanente.`, code_deleteAccountConfirm: `¿Estás seguro de que deseas eliminar tu cuenta |DISPLAYNAME| (|EMAIL|)? Esta acción es permanente.`,
code_archgun: `Archcañón`, code_archgun: `Archcañón`,
@ -84,6 +85,7 @@ dict = {
inventory_moaPets: `Moas`, inventory_moaPets: `Moas`,
inventory_kubrowPets: `Bestias`, inventory_kubrowPets: `Bestias`,
inventory_evolutionProgress: `Progreso de evolución Incarnon`, inventory_evolutionProgress: `Progreso de evolución Incarnon`,
inventory_Boosters: `Potenciadores`,
inventory_bulkAddSuits: `Agregar Warframes faltantes`, inventory_bulkAddSuits: `Agregar Warframes faltantes`,
inventory_bulkAddWeapons: `Agregar armas faltantes`, inventory_bulkAddWeapons: `Agregar armas faltantes`,
inventory_bulkAddSpaceSuits: `Agregar Archwings faltantes`, inventory_bulkAddSpaceSuits: `Agregar Archwings faltantes`,
@ -98,7 +100,7 @@ dict = {
inventory_bulkRankUpSentinels: `Maximizar rango de todos los centinelas`, inventory_bulkRankUpSentinels: `Maximizar rango de todos los centinelas`,
inventory_bulkRankUpSentinelWeapons: `Maximizar rango de todas las armas de centinela`, inventory_bulkRankUpSentinelWeapons: `Maximizar rango de todas las armas de centinela`,
inventory_bulkRankUpEvolutionProgress: `Maximizar todo el progreso de evolución Incarnon`, inventory_bulkRankUpEvolutionProgress: `Maximizar todo el progreso de evolución Incarnon`,
inventory_Boosters: `Potenciadores`, inventory_maxPlexus: `Rango máximo de Plexus`,
quests_list: `Misiones`, quests_list: `Misiones`,
quests_completeAll: `Completar todas las misiones`, quests_completeAll: `Completar todas las misiones`,
@ -133,6 +135,10 @@ dict = {
cheats_infiniteRegalAya: `Aya Real infinita`, cheats_infiniteRegalAya: `Aya Real infinita`,
cheats_infiniteHelminthMaterials: `Materiales Helminto infinitos`, cheats_infiniteHelminthMaterials: `Materiales Helminto infinitos`,
cheats_claimingBlueprintRefundsIngredients: `Reclamar ingredientes devueltos por planos`, cheats_claimingBlueprintRefundsIngredients: `Reclamar ingredientes devueltos por planos`,
cheats_dontSubtractPurchaseCreditCost: `No restar costo en créditos de la compra`,
cheats_dontSubtractPurchasePlatinumCost: `No restar costo en platino de la compra`,
cheats_dontSubtractPurchaseItemCost: `No restar costo de ítem en la compra`,
cheats_dontSubtractPurchaseStandingCost: `No restar costo en reputación de la compra`,
cheats_dontSubtractVoidTraces: `No descontar vestigios del Vacío`, cheats_dontSubtractVoidTraces: `No descontar vestigios del Vacío`,
cheats_dontSubtractConsumables: `No restar consumibles`, cheats_dontSubtractConsumables: `No restar consumibles`,
cheats_unlockAllShipFeatures: `Desbloquear todas las funciones de nave`, cheats_unlockAllShipFeatures: `Desbloquear todas las funciones de nave`,
@ -153,6 +159,7 @@ dict = {
cheats_noDeathMarks: `Sin marcas de muerte`, cheats_noDeathMarks: `Sin marcas de muerte`,
cheats_noKimCooldowns: `Sin tiempo de espera para conversaciones KIM`, cheats_noKimCooldowns: `Sin tiempo de espera para conversaciones KIM`,
cheats_syndicateMissionsRepeatable: `Misiones de sindicato rejugables`, cheats_syndicateMissionsRepeatable: `Misiones de sindicato rejugables`,
cheats_unlockAllProfitTakerStages: `Deslobquea todas las etapas del Roba-ganancias`,
cheats_instantFinishRivenChallenge: `Terminar desafío de agrietado inmediatamente`, cheats_instantFinishRivenChallenge: `Terminar desafío de agrietado inmediatamente`,
cheats_instantResourceExtractorDrones: `Drones de extracción de recursos instantáneos`, cheats_instantResourceExtractorDrones: `Drones de extracción de recursos instantáneos`,
cheats_noResourceExtractorDronesDamage: `Sin daño a los drones extractores de recursos`, cheats_noResourceExtractorDronesDamage: `Sin daño a los drones extractores de recursos`,
@ -163,9 +170,10 @@ dict = {
cheats_noDojoResearchCosts: `Sin costo de investigación del dojo`, cheats_noDojoResearchCosts: `Sin costo de investigación del dojo`,
cheats_noDojoResearchTime: `Sin tiempo de investigación del dojo`, cheats_noDojoResearchTime: `Sin tiempo de investigación del dojo`,
cheats_fastClanAscension: `Ascenso rápido del clan`, cheats_fastClanAscension: `Ascenso rápido del clan`,
cheats_missionsCanGiveAllRelics: `Las misiones pueden otorgar todas las reliquias`,
cheats_spoofMasteryRank: `Rango de maestría simulado (-1 para desactivar)`, cheats_spoofMasteryRank: `Rango de maestría simulado (-1 para desactivar)`,
cheats_nightwaveStandingMultiplier: `Multiplicador de Reputación de Onda Nocturna`, cheats_nightwaveStandingMultiplier: `Multiplicador de Reputación de Onda Nocturna`,
cheats_saveSettings: `Guardar configuración`, cheats_save: `Guardar`,
cheats_account: `Cuenta`, cheats_account: `Cuenta`,
cheats_unlockAllFocusSchools: `Desbloquear todas las escuelas de enfoque`, cheats_unlockAllFocusSchools: `Desbloquear todas las escuelas de enfoque`,
cheats_helminthUnlockAll: `Subir al máximo el Helminto`, cheats_helminthUnlockAll: `Subir al máximo el Helminto`,
@ -183,7 +191,7 @@ dict = {
upgrade_WarframeAbilityDuration: `+|VAL|% de duración de habilidades`, upgrade_WarframeAbilityDuration: `+|VAL|% de duración de habilidades`,
upgrade_WarframeAbilityStrength: `+|VAL|% de fuerza de habilidades`, upgrade_WarframeAbilityStrength: `+|VAL|% de fuerza de habilidades`,
upgrade_WarframeArmourMax: `+|VAL| de armadura`, upgrade_WarframeArmourMax: `+|VAL| de armadura`,
upgrade_WarframeBlastProc: `+|VAL| de escudos al infligir estado de explosión`, upgrade_WarframeBlastProc: `+|VAL| de escudos al matar con daño de explosión`,
upgrade_WarframeCastingSpeed: `+|VAL|% de velocidad de lanzamiento de habilidades`, upgrade_WarframeCastingSpeed: `+|VAL|% de velocidad de lanzamiento de habilidades`,
upgrade_WarframeCorrosiveDamageBoost: `+|VAL|% de daño de habilidades a enemigos con estado corrosivo`, upgrade_WarframeCorrosiveDamageBoost: `+|VAL|% de daño de habilidades a enemigos con estado corrosivo`,
upgrade_WarframeCorrosiveStack: `Aumenta los acumuladores máximos de estado corrosivo en +|VAL|`, upgrade_WarframeCorrosiveStack: `Aumenta los acumuladores máximos de estado corrosivo en +|VAL|`,

View File

@ -3,7 +3,8 @@ dict = {
general_inventoryUpdateNote: `Note : Les changements effectués ici seront appliqués lors de la syncrhonisation. Visiter la navigation appliquera les changements apportés à l'inventaire.`, general_inventoryUpdateNote: `Note : Les changements effectués ici seront appliqués lors de la syncrhonisation. Visiter la navigation appliquera les changements apportés à l'inventaire.`,
general_addButton: `Ajouter`, general_addButton: `Ajouter`,
general_bulkActions: `Action groupée`, general_bulkActions: `Action groupée`,
code_nonValidAuthz: `Informations de connexion invalides`, code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
code_changeNameConfirm: `Nouveau nom du compte :`, code_changeNameConfirm: `Nouveau nom du compte :`,
code_deleteAccountConfirm: `Supprimer |DISPLAYNAME| (|EMAIL|) ? Cette action est irreversible.`, code_deleteAccountConfirm: `Supprimer |DISPLAYNAME| (|EMAIL|) ? Cette action est irreversible.`,
code_archgun: `Archgun`, code_archgun: `Archgun`,
@ -84,6 +85,7 @@ dict = {
inventory_moaPets: `Moas`, inventory_moaPets: `Moas`,
inventory_kubrowPets: `Bêtes`, inventory_kubrowPets: `Bêtes`,
inventory_evolutionProgress: `Progrès de l'évolution Incarnon`, inventory_evolutionProgress: `Progrès de l'évolution Incarnon`,
inventory_Boosters: `[UNTRANSLATED] Boosters`,
inventory_bulkAddSuits: `Ajouter les Warframes manquantes`, inventory_bulkAddSuits: `Ajouter les Warframes manquantes`,
inventory_bulkAddWeapons: `Ajouter les armes manquantes`, inventory_bulkAddWeapons: `Ajouter les armes manquantes`,
inventory_bulkAddSpaceSuits: `Ajouter les Archwings manquants`, inventory_bulkAddSpaceSuits: `Ajouter les Archwings manquants`,
@ -98,7 +100,7 @@ dict = {
inventory_bulkRankUpSentinels: `Toutes les Sentinelles au rang max`, inventory_bulkRankUpSentinels: `Toutes les Sentinelles au rang max`,
inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles au rang max`, inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles au rang max`,
inventory_bulkRankUpEvolutionProgress: `Toutes les évolutions Incarnon au rang max`, inventory_bulkRankUpEvolutionProgress: `Toutes les évolutions Incarnon au rang max`,
inventory_Boosters: `[UNTRANSLATED] Boosters`, inventory_maxPlexus: `[UNTRANSLATED] Max Rank Plexus`,
quests_list: `Quêtes`, quests_list: `Quêtes`,
quests_completeAll: `Compléter toutes les quêtes`, quests_completeAll: `Compléter toutes les quêtes`,
@ -133,11 +135,15 @@ dict = {
cheats_infiniteRegalAya: `Aya Raffiné infini`, cheats_infiniteRegalAya: `Aya Raffiné infini`,
cheats_infiniteHelminthMaterials: `Ressources d'Helminth infinies`, cheats_infiniteHelminthMaterials: `Ressources d'Helminth infinies`,
cheats_claimingBlueprintRefundsIngredients: `Récupérer les items rend les ressources`, cheats_claimingBlueprintRefundsIngredients: `Récupérer les items rend les ressources`,
cheats_dontSubtractPurchaseCreditCost: `[UNTRANSLATED] Don't Subtract Purchase Credit Cost`,
cheats_dontSubtractPurchasePlatinumCost: `[UNTRANSLATED] Don't Subtract Purchase Platinum Cost`,
cheats_dontSubtractPurchaseItemCost: `[UNTRANSLATED] Don't Subtract Purchase Item Cost`,
cheats_dontSubtractPurchaseStandingCost: `[UNTRANSLATED] Don't Subtract Purchase Standing Cost`,
cheats_dontSubtractVoidTraces: `Ne pas consommer de Void Traces`, cheats_dontSubtractVoidTraces: `Ne pas consommer de Void Traces`,
cheats_dontSubtractConsumables: `Ne pas retirer de consommables`, cheats_dontSubtractConsumables: `Ne pas retirer de consommables`,
cheats_unlockAllShipFeatures: `Débloquer tous les segments du vaisseau`, cheats_unlockAllShipFeatures: `Débloquer tous les segments du vaisseau`,
cheats_unlockAllShipDecorations: `Débloquer toutes les décorations du vaisseau`, cheats_unlockAllShipDecorations: `Débloquer toutes les décorations du vaisseau`,
cheats_unlockAllFlavourItems: `Débloquer tous les <abbr title=\"Animations, Glyphes, Palettes, etc.\">Flavor Items</abbr>`, cheats_unlockAllFlavourItems: `Débloquer tous les <abbr title="Animations, Glyphes, Palettes, etc.">Flavor Items</abbr>`,
cheats_unlockAllSkins: `Débloquer tous les skins`, cheats_unlockAllSkins: `Débloquer tous les skins`,
cheats_unlockAllCapturaScenes: `Débloquer toutes les scènes captura`, cheats_unlockAllCapturaScenes: `Débloquer toutes les scènes captura`,
cheats_unlockAllDecoRecipes: `Débloquer toutes les recherches dojo`, cheats_unlockAllDecoRecipes: `Débloquer toutes les recherches dojo`,
@ -153,6 +159,7 @@ dict = {
cheats_noDeathMarks: `Aucune marque d'assassin`, cheats_noDeathMarks: `Aucune marque d'assassin`,
cheats_noKimCooldowns: `Aucun cooldown sur le KIM`, cheats_noKimCooldowns: `Aucun cooldown sur le KIM`,
cheats_syndicateMissionsRepeatable: `Mission syndicat répétables`, cheats_syndicateMissionsRepeatable: `Mission syndicat répétables`,
cheats_unlockAllProfitTakerStages: `[UNTRANSLATED] Unlock All Profit Taker Stages`,
cheats_instantFinishRivenChallenge: `Débloquer le challenge Riven instantanément`, cheats_instantFinishRivenChallenge: `Débloquer le challenge Riven instantanément`,
cheats_instantResourceExtractorDrones: `Ressources de drones d'extraction instantannées`, cheats_instantResourceExtractorDrones: `Ressources de drones d'extraction instantannées`,
cheats_noResourceExtractorDronesDamage: `Aucun dégâts aux drones d'extraction de resources`, cheats_noResourceExtractorDronesDamage: `Aucun dégâts aux drones d'extraction de resources`,
@ -163,9 +170,10 @@ dict = {
cheats_noDojoResearchCosts: `Aucun coût de recherche (Dojo)`, cheats_noDojoResearchCosts: `Aucun coût de recherche (Dojo)`,
cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`, cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`,
cheats_fastClanAscension: `Ascension de clan rapide`, cheats_fastClanAscension: `Ascension de clan rapide`,
cheats_missionsCanGiveAllRelics: `[UNTRANSLATED] Missions Can Give All Relics`,
cheats_spoofMasteryRank: `Rang de maîtrise personnalisé (-1 pour désactiver)`, cheats_spoofMasteryRank: `Rang de maîtrise personnalisé (-1 pour désactiver)`,
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`, cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
cheats_saveSettings: `Sauvegarder les paramètres`, cheats_save: `[UNTRANSLATED] Save`,
cheats_account: `Compte`, cheats_account: `Compte`,
cheats_unlockAllFocusSchools: `Débloquer toutes les écoles de focus`, cheats_unlockAllFocusSchools: `Débloquer toutes les écoles de focus`,
cheats_helminthUnlockAll: `Helminth niveau max`, cheats_helminthUnlockAll: `Helminth niveau max`,
@ -183,7 +191,7 @@ dict = {
upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`, upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`,
upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`, upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`,
upgrade_WarframeArmourMax: `[UNTRANSLATED] +|VAL| Armor`, upgrade_WarframeArmourMax: `[UNTRANSLATED] +|VAL| Armor`,
upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on inflicting Blast Status`, upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on kill with Blast Damage`,
upgrade_WarframeCastingSpeed: `[UNTRANSLATED] +|VAL|% Casting Speed`, upgrade_WarframeCastingSpeed: `[UNTRANSLATED] +|VAL|% Casting Speed`,
upgrade_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`, upgrade_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`,
upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`, upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`,

View File

@ -3,7 +3,8 @@ dict = {
general_inventoryUpdateNote: `Примечание: изменения, внесенные здесь, отобразятся в игре только после повторной загрузки вашего инвентаря. Посещение навигации — самый простой способ этого добиться.`, general_inventoryUpdateNote: `Примечание: изменения, внесенные здесь, отобразятся в игре только после повторной загрузки вашего инвентаря. Посещение навигации — самый простой способ этого добиться.`,
general_addButton: `Добавить`, general_addButton: `Добавить`,
general_bulkActions: `Массовые действия`, general_bulkActions: `Массовые действия`,
code_nonValidAuthz: `Ваши данные больше не действительны.`, code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
code_changeNameConfirm: `Какое имя вы хотите установить для своей учетной записи?`, code_changeNameConfirm: `Какое имя вы хотите установить для своей учетной записи?`,
code_deleteAccountConfirm: `Вы уверены, что хотите удалить аккаунт |DISPLAYNAME| (|EMAIL|)? Это действие нельзя отменить.`, code_deleteAccountConfirm: `Вы уверены, что хотите удалить аккаунт |DISPLAYNAME| (|EMAIL|)? Это действие нельзя отменить.`,
code_archgun: `Арч-Пушка`, code_archgun: `Арч-Пушка`,
@ -84,6 +85,7 @@ dict = {
inventory_moaPets: `МОА`, inventory_moaPets: `МОА`,
inventory_kubrowPets: `Звери`, inventory_kubrowPets: `Звери`,
inventory_evolutionProgress: `Прогресс эволюции Инкарнонов`, inventory_evolutionProgress: `Прогресс эволюции Инкарнонов`,
inventory_Boosters: `[UNTRANSLATED] Boosters`,
inventory_bulkAddSuits: `Добавить отсутствующие варфреймы`, inventory_bulkAddSuits: `Добавить отсутствующие варфреймы`,
inventory_bulkAddWeapons: `Добавить отсутствующее оружие`, inventory_bulkAddWeapons: `Добавить отсутствующее оружие`,
inventory_bulkAddSpaceSuits: `Добавить отсутствующие арчвинги`, inventory_bulkAddSpaceSuits: `Добавить отсутствующие арчвинги`,
@ -98,7 +100,7 @@ dict = {
inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`, inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`,
inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`, inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`,
inventory_bulkRankUpEvolutionProgress: `Максимальный ранг всех эволюций Инкарнонов`, inventory_bulkRankUpEvolutionProgress: `Максимальный ранг всех эволюций Инкарнонов`,
inventory_Boosters: `[UNTRANSLATED] Boosters`, inventory_maxPlexus: `[UNTRANSLATED] Max Rank Plexus`,
quests_list: `Квесты`, quests_list: `Квесты`,
quests_completeAll: `Завершить все квесты`, quests_completeAll: `Завершить все квесты`,
@ -133,11 +135,15 @@ dict = {
cheats_infiniteRegalAya: `Бесконечная Королевская Айя`, cheats_infiniteRegalAya: `Бесконечная Королевская Айя`,
cheats_infiniteHelminthMaterials: `Бесконечные Выделения Гельминта`, cheats_infiniteHelminthMaterials: `Бесконечные Выделения Гельминта`,
cheats_claimingBlueprintRefundsIngredients: `[UNTRANSLATED] Claiming Blueprint Refunds Ingredients`, cheats_claimingBlueprintRefundsIngredients: `[UNTRANSLATED] Claiming Blueprint Refunds Ingredients`,
cheats_dontSubtractPurchaseCreditCost: `[UNTRANSLATED] Don't Subtract Purchase Credit Cost`,
cheats_dontSubtractPurchasePlatinumCost: `[UNTRANSLATED] Don't Subtract Purchase Platinum Cost`,
cheats_dontSubtractPurchaseItemCost: `[UNTRANSLATED] Don't Subtract Purchase Item Cost`,
cheats_dontSubtractPurchaseStandingCost: `[UNTRANSLATED] Don't Subtract Purchase Standing Cost`,
cheats_dontSubtractVoidTraces: `[UNTRANSLATED] Don't Subtract Void Traces`, cheats_dontSubtractVoidTraces: `[UNTRANSLATED] Don't Subtract Void Traces`,
cheats_dontSubtractConsumables: `Не уменьшать количество расходников`, cheats_dontSubtractConsumables: `Не уменьшать количество расходников`,
cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`, cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`,
cheats_unlockAllShipDecorations: `Разблокировать все украшения корабля`, cheats_unlockAllShipDecorations: `Разблокировать все украшения корабля`,
cheats_unlockAllFlavourItems: `Разблокировать все <abbr title=\"Наборы анимаций, глифы, палитры и т. д.\">уникальные предметы</abbr>`, cheats_unlockAllFlavourItems: `Разблокировать все <abbr title="Наборы анимаций, глифы, палитры и т. д.">уникальные предметы</abbr>`,
cheats_unlockAllSkins: `Разблокировать все скины`, cheats_unlockAllSkins: `Разблокировать все скины`,
cheats_unlockAllCapturaScenes: `Разблокировать все сцены Каптуры`, cheats_unlockAllCapturaScenes: `Разблокировать все сцены Каптуры`,
cheats_unlockAllDecoRecipes: `Разблокировать все рецепты декораций Дoдзё`, cheats_unlockAllDecoRecipes: `Разблокировать все рецепты декораций Дoдзё`,
@ -153,6 +159,7 @@ dict = {
cheats_noDeathMarks: `Без меток сметри`, cheats_noDeathMarks: `Без меток сметри`,
cheats_noKimCooldowns: `Чаты KIM без кулдауна`, cheats_noKimCooldowns: `Чаты KIM без кулдауна`,
cheats_syndicateMissionsRepeatable: `[UNTRANSLATED] Syndicate Missions Repeatable`, cheats_syndicateMissionsRepeatable: `[UNTRANSLATED] Syndicate Missions Repeatable`,
cheats_unlockAllProfitTakerStages: `[UNTRANSLATED] Unlock All Profit Taker Stages`,
cheats_instantFinishRivenChallenge: `[UNTRANSLATED] Instant Finish Riven Challenge`, cheats_instantFinishRivenChallenge: `[UNTRANSLATED] Instant Finish Riven Challenge`,
cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`, cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`,
cheats_noResourceExtractorDronesDamage: `Без урона по дронам-сборщикам`, cheats_noResourceExtractorDronesDamage: `Без урона по дронам-сборщикам`,
@ -163,9 +170,10 @@ dict = {
cheats_noDojoResearchCosts: `Бесплатные Исследование Додзё`, cheats_noDojoResearchCosts: `Бесплатные Исследование Додзё`,
cheats_noDojoResearchTime: `Мгновенные Исследование Додзё`, cheats_noDojoResearchTime: `Мгновенные Исследование Додзё`,
cheats_fastClanAscension: `Мгновенное Вознесение Клана`, cheats_fastClanAscension: `Мгновенное Вознесение Клана`,
cheats_missionsCanGiveAllRelics: `[UNTRANSLATED] Missions Can Give All Relics`,
cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`, cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`,
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`, cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
cheats_saveSettings: `Сохранить настройки`, cheats_save: `[UNTRANSLATED] Save`,
cheats_account: `Аккаунт`, cheats_account: `Аккаунт`,
cheats_unlockAllFocusSchools: `Разблокировать все школы фокуса`, cheats_unlockAllFocusSchools: `Разблокировать все школы фокуса`,
cheats_helminthUnlockAll: `Полностью улучшить Гельминта`, cheats_helminthUnlockAll: `Полностью улучшить Гельминта`,
@ -183,7 +191,7 @@ dict = {
upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`, upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`,
upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`, upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`,
upgrade_WarframeArmourMax: `[UNTRANSLATED] +|VAL| Armor`, upgrade_WarframeArmourMax: `[UNTRANSLATED] +|VAL| Armor`,
upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on inflicting Blast Status`, upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on kill with Blast Damage`,
upgrade_WarframeCastingSpeed: `[UNTRANSLATED] +|VAL|% Casting Speed`, upgrade_WarframeCastingSpeed: `[UNTRANSLATED] +|VAL|% Casting Speed`,
upgrade_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`, upgrade_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`,
upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`, upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`,

View File

@ -3,7 +3,8 @@ dict = {
general_inventoryUpdateNote: `注意:此处所做的更改只有在游戏同步仓库后才会生效。您可以通过访问星图来触发仓库更新。`, general_inventoryUpdateNote: `注意:此处所做的更改只有在游戏同步仓库后才会生效。您可以通过访问星图来触发仓库更新。`,
general_addButton: `添加`, general_addButton: `添加`,
general_bulkActions: `批量操作`, general_bulkActions: `批量操作`,
code_nonValidAuthz: `您的登录凭证已失效。`, code_loginFail: `登录失败。请检查邮箱和密码。`,
code_regFail: `注册失败。账号已存在。`,
code_changeNameConfirm: `您想将账户名称更改为什么?`, code_changeNameConfirm: `您想将账户名称更改为什么?`,
code_deleteAccountConfirm: `确定要删除账户 |DISPLAYNAME| (|EMAIL|) 吗?此操作不可撤销。`, code_deleteAccountConfirm: `确定要删除账户 |DISPLAYNAME| (|EMAIL|) 吗?此操作不可撤销。`,
code_archgun: `空战`, code_archgun: `空战`,
@ -25,7 +26,7 @@ dict = {
code_renamePrompt: `输入新的自定义名称:`, code_renamePrompt: `输入新的自定义名称:`,
code_remove: `移除`, code_remove: `移除`,
code_addItemsConfirm: `确定要向账户添加 |COUNT| 件物品吗?`, code_addItemsConfirm: `确定要向账户添加 |COUNT| 件物品吗?`,
code_succRankUp: `[UNTRANSLATED] Successfully ranked up.`, code_succRankUp: `等级已提升`,
code_noEquipmentToRankUp: `没有可升级的装备。`, code_noEquipmentToRankUp: `没有可升级的装备。`,
code_succAdded: `已成功添加。`, code_succAdded: `已成功添加。`,
code_succRemoved: `已成功移除。`, code_succRemoved: `已成功移除。`,
@ -34,8 +35,8 @@ dict = {
code_rerollsNumber: `洗卡次数`, code_rerollsNumber: `洗卡次数`,
code_viewStats: `查看属性`, code_viewStats: `查看属性`,
code_rank: `等级`, code_rank: `等级`,
code_rankUp: `[UNTRANSLATED] Rank up`, code_rankUp: `等级提升`,
code_rankDown: `[UNTRANSLATED] Rank down`, code_rankDown: `等级下降`,
code_count: `数量`, code_count: `数量`,
code_focusAllUnlocked: `所有专精学派均已解锁。`, code_focusAllUnlocked: `所有专精学派均已解锁。`,
code_focusUnlocked: `已解锁 |COUNT| 个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新。`, code_focusUnlocked: `已解锁 |COUNT| 个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新。`,
@ -84,6 +85,7 @@ dict = {
inventory_moaPets: `恐鸟`, inventory_moaPets: `恐鸟`,
inventory_kubrowPets: `动物同伴`, inventory_kubrowPets: `动物同伴`,
inventory_evolutionProgress: `灵化之源进度`, inventory_evolutionProgress: `灵化之源进度`,
inventory_Boosters: `加成器`,
inventory_bulkAddSuits: `添加缺失战甲`, inventory_bulkAddSuits: `添加缺失战甲`,
inventory_bulkAddWeapons: `添加缺失武器`, inventory_bulkAddWeapons: `添加缺失武器`,
inventory_bulkAddSpaceSuits: `添加缺失Archwing`, inventory_bulkAddSpaceSuits: `添加缺失Archwing`,
@ -98,7 +100,7 @@ dict = {
inventory_bulkRankUpSentinels: `所有守护升满级`, inventory_bulkRankUpSentinels: `所有守护升满级`,
inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`, inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
inventory_bulkRankUpEvolutionProgress: `所有灵化之源最大等级`, inventory_bulkRankUpEvolutionProgress: `所有灵化之源最大等级`,
inventory_Boosters: `加成器`, inventory_maxPlexus: `最大深控等级`,
quests_list: `任务`, quests_list: `任务`,
quests_completeAll: `完成所有任务`, quests_completeAll: `完成所有任务`,
@ -133,11 +135,15 @@ dict = {
cheats_infiniteRegalAya: `无限御品阿耶`, cheats_infiniteRegalAya: `无限御品阿耶`,
cheats_infiniteHelminthMaterials: `无限Helminth材料`, cheats_infiniteHelminthMaterials: `无限Helminth材料`,
cheats_claimingBlueprintRefundsIngredients: `取消蓝图制造时返还材料`, cheats_claimingBlueprintRefundsIngredients: `取消蓝图制造时返还材料`,
cheats_dontSubtractPurchaseCreditCost: `不减少现金花费`,
cheats_dontSubtractPurchasePlatinumCost: `不减少白金花费`,
cheats_dontSubtractPurchaseItemCost: `不减少物品花费`,
cheats_dontSubtractPurchaseStandingCost: `不减少声望花费`,
cheats_dontSubtractVoidTraces: `虚空光体无消耗`, cheats_dontSubtractVoidTraces: `虚空光体无消耗`,
cheats_dontSubtractConsumables: `消耗物品使用时无损耗`, cheats_dontSubtractConsumables: `消耗物品使用时无损耗`,
cheats_unlockAllShipFeatures: `解锁所有飞船功能`, cheats_unlockAllShipFeatures: `解锁所有飞船功能`,
cheats_unlockAllShipDecorations: `解锁所有飞船装饰`, cheats_unlockAllShipDecorations: `解锁所有飞船装饰`,
cheats_unlockAllFlavourItems: `解锁所有<abbr title=\"动画组合、图标、调色板等\">装饰物品</abbr>`, cheats_unlockAllFlavourItems: `解锁所有<abbr title="动画组合、图标、调色板等">装饰物品</abbr>`,
cheats_unlockAllSkins: `解锁所有外观`, cheats_unlockAllSkins: `解锁所有外观`,
cheats_unlockAllCapturaScenes: `解锁所有Captura场景`, cheats_unlockAllCapturaScenes: `解锁所有Captura场景`,
cheats_unlockAllDecoRecipes: `解锁所有道场配方`, cheats_unlockAllDecoRecipes: `解锁所有道场配方`,
@ -153,6 +159,7 @@ dict = {
cheats_noDeathMarks: `无死亡标记(不会被 Stalker/Grustrag 三霸/Zanuka 猎人等标记)`, cheats_noDeathMarks: `无死亡标记(不会被 Stalker/Grustrag 三霸/Zanuka 猎人等标记)`,
cheats_noKimCooldowns: `无 KIM 冷却时间`, cheats_noKimCooldowns: `无 KIM 冷却时间`,
cheats_syndicateMissionsRepeatable: `集团任务可重复`, cheats_syndicateMissionsRepeatable: `集团任务可重复`,
cheats_unlockAllProfitTakerStages: `解锁利润收割者圆蛛所有阶段`,
cheats_instantFinishRivenChallenge: `立即完成裂罅挑战`, cheats_instantFinishRivenChallenge: `立即完成裂罅挑战`,
cheats_instantResourceExtractorDrones: `即时资源采集无人机`, cheats_instantResourceExtractorDrones: `即时资源采集无人机`,
cheats_noResourceExtractorDronesDamage: `资源提取器不会损毁`, cheats_noResourceExtractorDronesDamage: `资源提取器不会损毁`,
@ -163,9 +170,10 @@ dict = {
cheats_noDojoResearchCosts: `无视道场研究消耗`, cheats_noDojoResearchCosts: `无视道场研究消耗`,
cheats_noDojoResearchTime: `无视道场研究时间`, cheats_noDojoResearchTime: `无视道场研究时间`,
cheats_fastClanAscension: `快速升级氏族`, cheats_fastClanAscension: `快速升级氏族`,
cheats_missionsCanGiveAllRelics: `任务可获取所有遗物`,
cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`, cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`,
cheats_nightwaveStandingMultiplier: `午夜电波声望倍率`, cheats_nightwaveStandingMultiplier: `午夜电波声望倍率`,
cheats_saveSettings: `保存设置`, cheats_save: `保存`,
cheats_account: `账户`, cheats_account: `账户`,
cheats_unlockAllFocusSchools: `解锁所有专精学派`, cheats_unlockAllFocusSchools: `解锁所有专精学派`,
cheats_helminthUnlockAll: `完全升级Helminth`, cheats_helminthUnlockAll: `完全升级Helminth`,
@ -176,56 +184,56 @@ dict = {
import_importNote: `您可以在此处提供完整或部分库存响应(客户端表示)。支持的所有字段<b>将被覆盖</b>到您的账户中。`, import_importNote: `您可以在此处提供完整或部分库存响应(客户端表示)。支持的所有字段<b>将被覆盖</b>到您的账户中。`,
import_submit: `提交`, import_submit: `提交`,
upgrade_Equilibrium: `[UNTRANSLATED] +|VAL|% Energy from Health pickups, +|VAL|% Health from Energy pickups`, upgrade_Equilibrium: `+|VAL|% 能量 来自生命球, +|VAL|% 生命 来自能量球`,
upgrade_MeleeCritDamage: `[UNTRANSLATED] +|VAL|% Melee Critical Damage`, upgrade_MeleeCritDamage: `+|VAL|% 近战暴击伤害`,
upgrade_PrimaryStatusChance: `[UNTRANSLATED] +|VAL|% Primary Status Chance`, upgrade_PrimaryStatusChance: `+|VAL|% 主武器触发几率`,
upgrade_SecondaryCritChance: `[UNTRANSLATED] +|VAL|% Secondary Critical Chance`, upgrade_SecondaryCritChance: `+|VAL|% 次要武器暴击几率`,
upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`, upgrade_WarframeAbilityDuration: `+|VAL|% 技能持续时间`,
upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`, upgrade_WarframeAbilityStrength: `+|VAL|% 技能强度`,
upgrade_WarframeArmourMax: `[UNTRANSLATED] +|VAL| Armor`, upgrade_WarframeArmourMax: `+|VAL| 护甲`,
upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on inflicting Blast Status`, upgrade_WarframeBlastProc: `+|VAL| 护盾在击杀时附带爆炸伤害`,
upgrade_WarframeCastingSpeed: `[UNTRANSLATED] +|VAL|% Casting Speed`, upgrade_WarframeCastingSpeed: `+|VAL|% 施放速度`,
upgrade_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`, upgrade_WarframeCorrosiveDamageBoost: `对受腐蚀状态影响的敌人 +|VAL|% 技能伤害`,
upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`, upgrade_WarframeCorrosiveStack: `腐蚀状态最大堆叠数 +|VAL|`,
upgrade_WarframeCritDamageBoost: `[UNTRANSLATED] +|VAL|% Melee Critical Damage (Doubles over 500 Energy)`, upgrade_WarframeCritDamageBoost: `+|VAL|% 近战暴击伤害 (500能量以上翻倍)`,
upgrade_WarframeElectricDamage: `[UNTRANSLATED] +|VAL1|% Primary Electricity Damage (+|VAL2|% per additional Shard)`, upgrade_WarframeElectricDamage: `+|VAL1|% 主武器伤害效果 (+|VAL2|% 每附加一个碎片)`,
upgrade_WarframeElectricDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Electricity Status`, upgrade_WarframeElectricDamageBoost: `对受电能状态影响的敌人 +|VAL|% 技能伤害`,
upgrade_WarframeEnergyMax: `[UNTRANSLATED] +|VAL| Energy Max`, upgrade_WarframeEnergyMax: `+|VAL| 最大能量`,
upgrade_WarframeGlobeEffectEnergy: `[UNTRANSLATED] +|VAL|% Energy Orb Effectiveness`, upgrade_WarframeGlobeEffectEnergy: `+|VAL|% 能量球效果`,
upgrade_WarframeGlobeEffectHealth: `[UNTRANSLATED] +|VAL|% Health Orb Effectiveness`, upgrade_WarframeGlobeEffectHealth: `+|VAL|% 生命球效果`,
upgrade_WarframeHealthMax: `[UNTRANSLATED] +|VAL| Health`, upgrade_WarframeHealthMax: `+|VAL| 生命`,
upgrade_WarframeHPBoostFromImpact: `[UNTRANSLATED] +|VAL1| Health per enemy killed with Blast Damage (Max |VAL2| Health)`, upgrade_WarframeHPBoostFromImpact: `每个被爆炸伤害击杀的敌人,补充 |VAL1|生命 (最大 |VAL2| 生命)`,
upgrade_WarframeParkourVelocity: `[UNTRANSLATED] +|VAL|% Parkour Velocity`, upgrade_WarframeParkourVelocity: `+|VAL|% 跑酷速度`,
upgrade_WarframeRadiationDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Radiation Status`, upgrade_WarframeRadiationDamageBoost: `对受辐射状态影响的敌人 +|VAL|% 技能伤害`,
upgrade_WarframeRegen: `[UNTRANSLATED] +|VAL| Health Regen/s`, upgrade_WarframeRegen: `+|VAL| 生命再生/s`,
upgrade_WarframeShieldMax: `[UNTRANSLATED] +|VAL| Shield`, upgrade_WarframeShieldMax: `+|VAL| 护盾`,
upgrade_WarframeStartingEnergy: `[UNTRANSLATED] +|VAL|% Energy on Spawn`, upgrade_WarframeStartingEnergy: `+|VAL|% 能量出生时`,
upgrade_WarframeToxinDamage: `[UNTRANSLATED] +|VAL|% Toxin Status Effect Damage`, upgrade_WarframeToxinDamage: `+|VAL|% 毒素伤害效果`,
upgrade_WarframeToxinHeal: `[UNTRANSLATED] +|VAL| Health on damaging enemies with Toxin Status`, upgrade_WarframeToxinHeal: `+|VAL| 生命 对毒素状态的敌人造成伤害时`,
upgrade_WeaponCritBoostFromHeat: `[UNTRANSLATED] +|VAL1|% Secondary Critical Chance per Heat-affected enemy killed (Max |VAL2|%)`, upgrade_WeaponCritBoostFromHeat: `每个被火焰伤害杀死的敌人, 增加|VAL1|% 次要武器暴击几率 (最大 |VAL2|%)`,
upgrade_AvatarAbilityRange: `[UNTRANSLATED] +7.5% Ability Range`, upgrade_AvatarAbilityRange: `+7.5% 技能范围`,
upgrade_AvatarAbilityEfficiency: `[UNTRANSLATED] +5% Ability Efficiency`, upgrade_AvatarAbilityEfficiency: `+5% 技能效率`,
upgrade_AvatarEnergyRegen: `[UNTRANSLATED] +0.5 Energy Regen/s`, upgrade_AvatarEnergyRegen: `+0.5 能量再生/秒`,
upgrade_AvatarEnemyRadar: `[UNTRANSLATED] +5m Enemy Radar`, upgrade_AvatarEnemyRadar: `+5米 敌方雷达`,
upgrade_AvatarLootRadar: `[UNTRANSLATED] +7m Loot Radar`, upgrade_AvatarLootRadar: `+7米 战利品雷达`,
upgrade_WeaponAmmoMax: `[UNTRANSLATED] +15% Ammo Max`, upgrade_WeaponAmmoMax: `+15% 弹药最大容量`,
upgrade_EnemyArmorReductionAura: `[UNTRANSLATED] -3% Enemy Armor`, upgrade_EnemyArmorReductionAura: `-3% 敌方护甲`,
upgrade_OnExecutionAmmo: `[UNTRANSLATED] 100% Primary and Secondary Magazine Refill on Mercy`, upgrade_OnExecutionAmmo: `怜悯之击 100% 补充主次要武器弹匣`,
upgrade_OnExecutionHealthDrop: `[UNTRANSLATED] 100% chance to drop a Health Orb on Mercy`, upgrade_OnExecutionHealthDrop: `怜悯之击 100% 几率 掉落生命球`,
upgrade_OnExecutionEnergyDrop: `[UNTRANSLATED] 50% chance to drop an Energy Orb on Mercy`, upgrade_OnExecutionEnergyDrop: `怜悯之击 50% 几率 掉落生命球`,
upgrade_OnFailHackReset: `[UNTRANSLATED] +50% to retry on Hacking failure`, upgrade_OnFailHackReset: `+50% 在入侵失败时重试`,
upgrade_DamageReductionOnHack: `[UNTRANSLATED] 75% Damage Reduction while Hacking`, upgrade_DamageReductionOnHack: `入侵时,+75% 伤害减免`,
upgrade_OnExecutionReviveCompanion: `[UNTRANSLATED] Mercy Kills reduce Companion Recovery by 15s`, upgrade_OnExecutionReviveCompanion: `怜悯之击 减少同伴复苏时间 15秒`,
upgrade_OnExecutionParkourSpeed: `[UNTRANSLATED] +60% Parkour Speed after a Mercy for 15s`, upgrade_OnExecutionParkourSpeed: `怜悯之击 15秒内 +60% 跑酷速度`,
upgrade_AvatarTimeLimitIncrease: `[UNTRANSLATED] s to Hacking`, upgrade_AvatarTimeLimitIncrease: `增加入侵限制时间`,
upgrade_ElectrifyOnHack: `[UNTRANSLATED] Shock enemies within 20m while Hacking`, upgrade_ElectrifyOnHack: `入侵时震慑20米之内的敌人`,
upgrade_OnExecutionTerrify: `[UNTRANSLATED] 50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`, upgrade_OnExecutionTerrify: `怜悯之击 50% 几率让 15米 以内的敌人恐慌`,
upgrade_OnHackLockers: `[UNTRANSLATED] Unlock 5 lockers within 20m after Hacking`, upgrade_OnHackLockers: `入侵后解锁20米内的5个储物柜`,
upgrade_OnExecutionBlind: `[UNTRANSLATED] Blind enemies within 18m on Mercy`, upgrade_OnExecutionBlind: `怜悯之击 致盲18米之内的敌人`,
upgrade_OnExecutionDrainPower: `[UNTRANSLATED] 100% chance for next ability cast to gain +50% Ability Strength on Mercy`, upgrade_OnExecutionDrainPower: `怜悯之击会使下一个技能有100%的机会获得+50%的技能强度`,
upgrade_OnHackSprintSpeed: `[UNTRANSLATED] +75% Sprint Speed for 15s after Hacking`, upgrade_OnHackSprintSpeed: `入侵后+75%冲刺速度持续15秒`,
upgrade_SwiftExecute: `[UNTRANSLATED] Speed of Mercy Kills increased by 50%`, upgrade_SwiftExecute: `怜悯之击速度提升50%`,
upgrade_OnHackInvis: `[UNTRANSLATED] Invisible for 15 seconds after hacking`, upgrade_OnHackInvis: `入侵后隐身15秒`,
prettier_sucks_ass: `` prettier_sucks_ass: ``
}; };