forked from OpenWF/SpaceNinjaServer
Compare commits
34 Commits
b98a88b700
...
3186ffe164
Author | SHA1 | Date | |
---|---|---|---|
3186ffe164 | |||
e686a2d028 | |||
88d4ba6340 | |||
05382beaaf | |||
e136c0494e | |||
ad7b5fc052 | |||
61a8d01f64 | |||
d78ca91d6c | |||
4ca4990f89 | |||
bf40155dd4 | |||
2e9d3c33b6 | |||
7c8e8fe049 | |||
0c4065619d | |||
dabca46e88 | |||
7819d87bbe | |||
b8b8b6a6c6 | |||
9af0e06b70 | |||
f8d0c9e0cb | |||
16e80acb53 | |||
6691d4e402 | |||
3dcd2663d3 | |||
ffeffe2796 | |||
a9f1368cb7 | |||
cccf6f04a5 | |||
1ead581780 | |||
145d21e30e | |||
6c2055a246 | |||
01e490768c | |||
2e8fe799d7 | |||
53976378bb | |||
4e832d3b2c | |||
8c1147998d | |||
3e99e069be | |||
9731004de6 |
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@ -1,6 +1,7 @@
|
||||
name: Build
|
||||
on:
|
||||
push: {}
|
||||
push:
|
||||
branches: ["main"]
|
||||
pull_request: {}
|
||||
jobs:
|
||||
build:
|
||||
|
25
.github/workflows/docker.yml
vendored
25
.github/workflows/docker.yml
vendored
@ -4,9 +4,9 @@ on:
|
||||
branches:
|
||||
- main
|
||||
jobs:
|
||||
docker:
|
||||
docker-amd64:
|
||||
if: github.repository == 'OpenWF/SpaceNinjaServer'
|
||||
runs-on: ubuntu-latest
|
||||
runs-on: amd64
|
||||
steps:
|
||||
- name: Set up Docker buildx
|
||||
uses: docker/setup-buildx-action@v3
|
||||
@ -18,8 +18,27 @@ jobs:
|
||||
- name: Build and push
|
||||
uses: docker/build-push-action@v6
|
||||
with:
|
||||
platforms: linux/amd64,linux/arm64
|
||||
platforms: linux/amd64
|
||||
push: true
|
||||
tags: |
|
||||
openwf/spaceninjaserver:latest
|
||||
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
|
||||
|
52
Dockerfile
52
Dockerfile
@ -1,53 +1,11 @@
|
||||
FROM node:18-alpine3.19
|
||||
FROM node:24-alpine3.21
|
||||
|
||||
ENV APP_MONGODB_URL=mongodb://mongodb:27017/openWF
|
||||
ENV APP_MY_ADDRESS=localhost
|
||||
ENV APP_HTTP_PORT=80
|
||||
ENV APP_HTTPS_PORT=443
|
||||
ENV APP_AUTO_CREATE_ACCOUNT=true
|
||||
ENV APP_SKIP_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
|
||||
RUN apk add --no-cache bash jq
|
||||
|
||||
COPY . /app
|
||||
WORKDIR /app
|
||||
|
||||
RUN npm i --omit=dev
|
||||
RUN npm run build
|
||||
|
||||
ENTRYPOINT ["/app/docker-entrypoint.sh"]
|
||||
|
@ -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 ]`.
|
||||
- `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.duviriOverride` can be set to `joy`, `anger`, `envy`, `sorrow`, or `fear` to lock the Duviri spiral.
|
||||
- `worldState.nightwaveOverride` will lock the nightwave season, assuming the client is new enough for it. Valid values:
|
||||
- `RadioLegionIntermission13Syndicate` for Nora's Mix Vol. 9
|
||||
- `RadioLegionIntermission12Syndicate` for Nora's Mix Vol. 8
|
||||
@ -33,3 +34,4 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi
|
||||
- `RadioLegion2Syndicate` for The Emissary
|
||||
- `RadioLegionIntermissionSyndicate` for Intermission I
|
||||
- `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`)
|
||||
|
@ -20,6 +20,10 @@
|
||||
"infiniteRegalAya": false,
|
||||
"infiniteHelminthMaterials": false,
|
||||
"claimingBlueprintRefundsIngredients": false,
|
||||
"dontSubtractPurchaseCreditCost": false,
|
||||
"dontSubtractPurchasePlatinumCost": false,
|
||||
"dontSubtractPurchaseItemCost": false,
|
||||
"dontSubtractPurchaseStandingCost": false,
|
||||
"dontSubtractVoidTraces": false,
|
||||
"dontSubtractConsumables": false,
|
||||
"unlockAllShipFeatures": false,
|
||||
@ -58,7 +62,9 @@
|
||||
"starDays": true,
|
||||
"eidolonOverride": "",
|
||||
"vallisOverride": "",
|
||||
"nightwaveOverride": ""
|
||||
"duviriOverride": "",
|
||||
"nightwaveOverride": "",
|
||||
"circuitGameModes": null
|
||||
},
|
||||
"dev": {
|
||||
"keepVendorsExpired": false
|
||||
|
@ -1,62 +1,20 @@
|
||||
services:
|
||||
spaceninjaserver:
|
||||
# build: .
|
||||
# The image to use. If you have an ARM CPU, replace 'latest' with 'latest-arm64'.
|
||||
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:
|
||||
- ./docker-data/static:/app/static/data
|
||||
- ./docker-data/conf:/app/conf
|
||||
- ./docker-data/static-data:/app/static/data
|
||||
- ./docker-data/logs:/app/logs
|
||||
ports:
|
||||
- 80:80
|
||||
- 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:
|
||||
- mongodb
|
||||
mongodb:
|
||||
@ -66,3 +24,4 @@ services:
|
||||
MONGO_INITDB_ROOT_PASSWORD: spaceninjaserver
|
||||
volumes:
|
||||
- ./docker-data/database:/data/db
|
||||
command: mongod --quiet --logpath /dev/null
|
||||
|
@ -1,24 +1,8 @@
|
||||
#!/bin/bash
|
||||
set -e
|
||||
|
||||
# Set up the configuration file using environment variables.
|
||||
echo '{
|
||||
"logger": {
|
||||
"files": true,
|
||||
"level": "trace",
|
||||
"__valid_levels": "fatal, error, warn, info, http, debug, trace"
|
||||
}
|
||||
}
|
||||
' > config.json
|
||||
if [ ! -f conf/config.json ]; then
|
||||
jq --arg value "mongodb://openwfagent:spaceninjaserver@mongodb:27017/" '.mongodbUrl = $value' /app/config.json.example > /app/conf/config.json
|
||||
fi
|
||||
|
||||
for config in $(env | grep "APP_")
|
||||
do
|
||||
var=$(echo "${config}" | tr '[:upper:]' '[:lower:]' | sed 's/app_//g' | sed -E 's/_([a-z])/\U\1/g' | sed 's/=.*//g')
|
||||
val=$(echo "${config}" | sed 's/.*=//g')
|
||||
jq --arg variable "$var" --arg value "$val" '.[$variable] += try [$value|fromjson][] catch $value' config.json > config.tmp
|
||||
mv config.tmp config.json
|
||||
done
|
||||
|
||||
npm i --omit=dev
|
||||
npm run build
|
||||
exec npm run start
|
||||
exec npm run start conf/config.json
|
||||
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -18,7 +18,7 @@
|
||||
"morgan": "^1.10.0",
|
||||
"ncp": "^2.0.0",
|
||||
"typescript": "^5.5",
|
||||
"warframe-public-export-plus": "^0.5.67",
|
||||
"warframe-public-export-plus": "^0.5.68",
|
||||
"warframe-riven-info": "^0.1.2",
|
||||
"winston": "^3.17.0",
|
||||
"winston-daily-rotate-file": "^5.0.0"
|
||||
@ -3814,9 +3814,9 @@
|
||||
}
|
||||
},
|
||||
"node_modules/warframe-public-export-plus": {
|
||||
"version": "0.5.67",
|
||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.67.tgz",
|
||||
"integrity": "sha512-LsnZD2E5PTA+5MK9kDGvM/hFDtg8sb0EwQ4hKH5ILqrSgz30a9W8785v77RSsL1AEVF8dfb/lZcSTCJq1DZHzQ=="
|
||||
"version": "0.5.68",
|
||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.68.tgz",
|
||||
"integrity": "sha512-KMmwCVeQ4k+EN73UZqxnM+qQdPsST8geWoJCP7US5LT6JcRxa8ptmqYXwCzaLtckBLZyVbamsxKZAxPPJckxsA=="
|
||||
},
|
||||
"node_modules/warframe-riven-info": {
|
||||
"version": "0.1.2",
|
||||
|
@ -25,7 +25,7 @@
|
||||
"morgan": "^1.10.0",
|
||||
"ncp": "^2.0.0",
|
||||
"typescript": "^5.5",
|
||||
"warframe-public-export-plus": "^0.5.67",
|
||||
"warframe-public-export-plus": "^0.5.68",
|
||||
"warframe-riven-info": "^0.1.2",
|
||||
"winston": "^3.17.0",
|
||||
"winston-daily-rotate-file": "^5.0.0"
|
||||
|
107
src/controllers/api/crewShipFusionController.ts
Normal file
107
src/controllers/api/crewShipFusionController.ts
Normal 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];
|
@ -43,7 +43,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
||||
inventory.FocusAbility ??= focusType;
|
||||
inventory.FocusUpgrades.push({ ItemType: focusType });
|
||||
if (inventory.FocusXP) {
|
||||
inventory.FocusXP[focusPolarity] -= cost;
|
||||
inventory.FocusXP[focusPolarity]! -= cost;
|
||||
}
|
||||
await inventory.save();
|
||||
res.json({
|
||||
@ -78,7 +78,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
||||
cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
|
||||
inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
|
||||
}
|
||||
inventory.FocusXP![focusPolarity] -= cost;
|
||||
inventory.FocusXP![focusPolarity]! -= cost;
|
||||
await inventory.save();
|
||||
res.json({
|
||||
FocusTypes: request.FocusTypes,
|
||||
@ -96,7 +96,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
||||
const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
|
||||
focusUpgradeDb.Level = focusUpgrade.Level;
|
||||
}
|
||||
inventory.FocusXP![focusPolarity] -= cost;
|
||||
inventory.FocusXP![focusPolarity]! -= cost;
|
||||
await inventory.save();
|
||||
res.json({
|
||||
FocusInfos: request.FocusInfos,
|
||||
@ -123,7 +123,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
||||
const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
|
||||
const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
|
||||
const inventory = await getInventory(accountId);
|
||||
inventory.FocusXP![focusPolarity] -= 750_000 * request.FocusTypes.length;
|
||||
inventory.FocusXP![focusPolarity]! -= 750_000 * request.FocusTypes.length;
|
||||
addMiscItems(inventory, [
|
||||
{
|
||||
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem",
|
||||
@ -168,8 +168,10 @@ export const focusController: RequestHandler = async (req, res) => {
|
||||
shard.ItemCount *= -1;
|
||||
}
|
||||
const inventory = await getInventory(accountId);
|
||||
inventory.FocusXP ??= { AP_POWER: 0, AP_TACTIC: 0, AP_DEFENSE: 0, AP_ATTACK: 0, AP_WARD: 0 };
|
||||
inventory.FocusXP[request.Polarity] += xp;
|
||||
const polarity = request.Polarity;
|
||||
inventory.FocusXP ??= {};
|
||||
inventory.FocusXP[polarity] ??= 0;
|
||||
inventory.FocusXP[polarity] += xp;
|
||||
addMiscItems(inventory, request.Shards);
|
||||
await inventory.save();
|
||||
break;
|
||||
|
@ -11,7 +11,7 @@ import {
|
||||
scaleRequiredCount,
|
||||
setGuildTechLogState
|
||||
} 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 {
|
||||
addCrewShipWeaponSkin,
|
||||
@ -442,6 +442,7 @@ const finishComponentRepair = (
|
||||
...(category == "CrewShipWeaponSkins"
|
||||
? addCrewShipWeaponSkin(inventory, salvageItem.ItemType, salvageItem.UpgradeFingerprint)
|
||||
: addEquipment(inventory, category, salvageItem.ItemType, {
|
||||
UpgradeType: ExportRailjackWeapons[salvageItem.ItemType].defaultUpgrades?.[0].ItemType,
|
||||
UpgradeFingerprint: salvageItem.UpgradeFingerprint
|
||||
})),
|
||||
...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, false)
|
||||
|
@ -30,8 +30,9 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
|
||||
const request = getJSONfromString<IShardInstallRequest>(String(req.body));
|
||||
const inventory = await getInventory(account._id.toString());
|
||||
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] = {
|
||||
UpgradeType: request.UpgradeType,
|
||||
@ -92,7 +93,8 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
|
||||
}
|
||||
|
||||
// remove from suit
|
||||
suit.ArchonCrystalUpgrades![request.Slot] = {};
|
||||
suit.ArchonCrystalUpgrades![request.Slot].UpgradeType = undefined;
|
||||
suit.ArchonCrystalUpgrades![request.Slot].Color = undefined;
|
||||
|
||||
await inventory.save();
|
||||
|
||||
|
@ -1,5 +1,6 @@
|
||||
import { version_compare } from "@/src/helpers/inventoryHelpers";
|
||||
import {
|
||||
antivirusMods,
|
||||
consumeModCharge,
|
||||
decodeNemesisGuess,
|
||||
encodeNemesisGuess,
|
||||
@ -16,6 +17,7 @@ import {
|
||||
IKnifeResponse
|
||||
} from "@/src/helpers/nemesisHelpers";
|
||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
||||
import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
||||
import { getAccountForRequest } from "@/src/services/loginService";
|
||||
@ -134,34 +136,38 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
||||
for (const upgrade of body.knife!.AttachedUpgrades) {
|
||||
switch (upgrade.ItemType) {
|
||||
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/GainAntivirusSmallOnSingleUseMod":
|
||||
antivirusGain += 10;
|
||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||
break;
|
||||
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
|
||||
antivirusGain += 15;
|
||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||
break;
|
||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
|
||||
antivirusGain += 10;
|
||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||
break;
|
||||
}
|
||||
}
|
||||
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) {
|
||||
inventory.Nemesis!.HenchmenKilled = 100;
|
||||
if (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();
|
||||
res.json(response);
|
||||
@ -198,16 +204,28 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
||||
guess[body.position].result = correct ? GUESS_CORRECT : GUESS_INCORRECT;
|
||||
inventory.Nemesis!.GuessHistory[inventory.Nemesis!.GuessHistory.length - 1] = encodeNemesisGuess(guess);
|
||||
|
||||
// Increase rank if incorrect
|
||||
let RankIncrease: number | undefined;
|
||||
if (!correct) {
|
||||
RankIncrease = 1;
|
||||
const response: INemesisRequiemResponse = {};
|
||||
if (correct) {
|
||||
if (body.position == 2) {
|
||||
// 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);
|
||||
inventory.Nemesis!.Rank = Math.min(inventory.Nemesis!.Rank + 1, manifest.systemIndexes.length - 1);
|
||||
inventory.Nemesis!.InfNodes = getInfNodes(manifest, inventory.Nemesis!.Rank);
|
||||
}
|
||||
await inventory.save();
|
||||
res.json({ RankIncrease });
|
||||
res.json(response);
|
||||
}
|
||||
} else if ((req.query.mode as string) == "rs") {
|
||||
// report spawn; POST but no application data in body
|
||||
@ -277,36 +295,15 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
||||
target: inventory.toJSON().Nemesis
|
||||
});
|
||||
} else if ((req.query.mode as string) == "w") {
|
||||
const inventory = await getInventory(
|
||||
account._id.toString(),
|
||||
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
|
||||
);
|
||||
const inventory = await getInventory(account._id.toString(), "Nemesis");
|
||||
//const body = getJSONfromString<INemesisWeakenRequest>(String(req.body));
|
||||
|
||||
inventory.Nemesis!.InfNodes = [
|
||||
{
|
||||
Node: getNemesisManifest(inventory.Nemesis!.manifest).showdownNode,
|
||||
Influence: 1
|
||||
}
|
||||
];
|
||||
inventory.Nemesis!.Weakened = true;
|
||||
// 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.
|
||||
|
||||
const response: IKnifeResponse & { target: INemesisClient } = {
|
||||
const response: INemesisWeakenResponse = {
|
||||
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);
|
||||
} else {
|
||||
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
||||
@ -362,11 +359,19 @@ interface INemesisRequiemRequest {
|
||||
knife?: IKnife;
|
||||
}
|
||||
|
||||
interface INemesisRequiemResponse extends IKnifeResponse {
|
||||
RankIncrease?: number;
|
||||
}
|
||||
|
||||
// interface INemesisWeakenRequest {
|
||||
// target: INemesisClient;
|
||||
// knife: IKnife;
|
||||
// }
|
||||
|
||||
interface INemesisWeakenResponse extends IKnifeResponse {
|
||||
target: INemesisClient;
|
||||
}
|
||||
|
||||
interface IKnife {
|
||||
Item: IEquipmentClient;
|
||||
Skins: IWeaponSkinClient[];
|
||||
@ -375,3 +380,18 @@ interface IKnife {
|
||||
AttachedUpgrades: IUpgradeClient[];
|
||||
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);
|
||||
}
|
||||
};
|
||||
|
@ -1,6 +1,7 @@
|
||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||
import { getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||
import { RequestHandler } from "express";
|
||||
|
||||
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 data = getJSONfromString<IRenamePetRequest>(String(req.body));
|
||||
const details = inventory.KubrowPets.id(data.petId)!.Details!;
|
||||
|
||||
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();
|
||||
res.json({
|
||||
...data,
|
||||
inventoryChanges: currencyChanges
|
||||
inventoryChanges: inventoryChanges
|
||||
});
|
||||
};
|
||||
|
||||
|
22
src/controllers/api/setSuitInfectionController.ts
Normal file
22
src/controllers/api/setSuitInfectionController.ts
Normal 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[];
|
||||
}
|
27
src/controllers/api/umbraController.ts
Normal file
27
src/controllers/api/umbraController.ts
Normal 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[];
|
||||
}
|
@ -4,6 +4,8 @@ import { getAccountForRequest } from "@/src/services/loginService";
|
||||
import { addChallenges, getInventory } from "@/src/services/inventoryService";
|
||||
import { IChallengeProgress, ISeasonChallenge } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||
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) => {
|
||||
const challenges = getJSONfromString<IUpdateChallengeProgressRequest>(String(req.body));
|
||||
@ -11,7 +13,7 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
||||
|
||||
const inventory = await getInventory(
|
||||
account._id.toString(),
|
||||
"ChallengeProgress SeasonChallengeHistory Affiliations"
|
||||
"ChallengesFixVersion ChallengeProgress SeasonChallengeHistory Affiliations"
|
||||
);
|
||||
let affiliationMods: IAffiliationMods[] = [];
|
||||
if (challenges.ChallengeProgress) {
|
||||
@ -22,15 +24,30 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
||||
challenges.SeasonChallengeCompletions
|
||||
);
|
||||
}
|
||||
if (challenges.SeasonChallengeHistory) {
|
||||
challenges.SeasonChallengeHistory.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 });
|
||||
}
|
||||
});
|
||||
for (const [key, value] of getEntriesUnsafe(challenges)) {
|
||||
switch (key) {
|
||||
case "ChallengesFixVersion":
|
||||
inventory.ChallengesFixVersion = value;
|
||||
break;
|
||||
|
||||
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":
|
||||
break;
|
||||
default:
|
||||
logger.warn(`unknown challenge progress entry`, { key, value });
|
||||
}
|
||||
}
|
||||
await inventory.save();
|
||||
|
||||
@ -40,6 +57,8 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
||||
};
|
||||
|
||||
interface IUpdateChallengeProgressRequest {
|
||||
ChallengePTS?: number;
|
||||
ChallengesFixVersion?: number;
|
||||
ChallengeProgress?: IChallengeProgress[];
|
||||
SeasonChallengeHistory?: ISeasonChallenge[];
|
||||
SeasonChallengeCompletions?: ISeasonChallenge[];
|
||||
|
@ -12,6 +12,7 @@ export const popArchonCrystalUpgradeController: RequestHandler = async (req, res
|
||||
);
|
||||
await inventory.save();
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
res.status(400).end();
|
||||
};
|
||||
|
@ -15,6 +15,7 @@ export const pushArchonCrystalUpgradeController: RequestHandler = async (req, re
|
||||
}
|
||||
await inventory.save();
|
||||
res.end();
|
||||
return;
|
||||
}
|
||||
}
|
||||
res.status(400).end();
|
||||
|
@ -1,15 +1,21 @@
|
||||
import { RequestHandler } from "express";
|
||||
import { updateConfig } from "@/src/services/configWatcherService";
|
||||
import { saveConfig } from "@/src/services/configWatcherService";
|
||||
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);
|
||||
if (isAdministrator(account)) {
|
||||
await updateConfig(String(req.body));
|
||||
const data = req.body as IUpdateConfigDataRequest;
|
||||
config[data.key] = data.value;
|
||||
await saveConfig();
|
||||
res.end();
|
||||
} else {
|
||||
res.status(401).end();
|
||||
}
|
||||
};
|
||||
|
||||
export { updateConfigDataController };
|
||||
interface IUpdateConfigDataRequest {
|
||||
key: keyof IConfig;
|
||||
value: never;
|
||||
}
|
||||
|
@ -248,7 +248,7 @@ const requiemMods: readonly string[] = [
|
||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod"
|
||||
];
|
||||
|
||||
const antivirusMods: readonly string[] = [
|
||||
export const antivirusMods: readonly string[] = [
|
||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
|
||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod",
|
||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod",
|
||||
|
@ -1,13 +1,13 @@
|
||||
// First, init config.
|
||||
import { config, loadConfig } from "@/src/services/configService";
|
||||
import { config, configPath, loadConfig } from "@/src/services/configService";
|
||||
import fs from "fs";
|
||||
try {
|
||||
loadConfig();
|
||||
} catch (e) {
|
||||
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 {
|
||||
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);
|
||||
}
|
||||
|
@ -251,12 +251,6 @@ const ArchonCrystalUpgradeSchema = new Schema<IArchonCrystalUpgrade>(
|
||||
{ _id: false }
|
||||
);
|
||||
|
||||
ArchonCrystalUpgradeSchema.set("toJSON", {
|
||||
transform(_document, returnedObject) {
|
||||
delete returnedObject.__v;
|
||||
}
|
||||
});
|
||||
|
||||
const boosterSchema = new Schema<IBooster>(
|
||||
{
|
||||
ExpiryDate: Number,
|
||||
@ -1079,6 +1073,11 @@ EquipmentSchema.set("toJSON", {
|
||||
if (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,
|
||||
Mailbox: MailboxSchema,
|
||||
HandlerPoints: Number,
|
||||
ChallengesFixVersion: { type: Number, default: 6 },
|
||||
ChallengesFixVersion: Number,
|
||||
PlayedParkourTutorial: Boolean,
|
||||
//ActiveLandscapeTraps: [Schema.Types.Mixed],
|
||||
//RepVotes: [Schema.Types.Mixed],
|
||||
|
@ -33,6 +33,7 @@ import { createAllianceController } from "@/src/controllers/api/createAllianceCo
|
||||
import { createGuildController } from "@/src/controllers/api/createGuildController";
|
||||
import { creditsController } from "@/src/controllers/api/creditsController";
|
||||
import { crewMembersController } from "@/src/controllers/api/crewMembersController";
|
||||
import { crewShipFusionController } from "@/src/controllers/api/crewShipFusionController";
|
||||
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
|
||||
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
||||
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 { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController";
|
||||
import { setShipVignetteController } from "@/src/controllers/api/setShipVignetteController";
|
||||
import { setSuitInfectionController } from "@/src/controllers/api/setSuitInfectionController";
|
||||
import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
|
||||
import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController";
|
||||
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 { tradingController } from "@/src/controllers/api/tradingController";
|
||||
import { trainingResultController } from "@/src/controllers/api/trainingResultController";
|
||||
import { umbraController } from "@/src/controllers/api/umbraController";
|
||||
import { unlockShipFeatureController } from "@/src/controllers/api/unlockShipFeatureController";
|
||||
import { updateAlignmentController } from "@/src/controllers/api/updateAlignmentController";
|
||||
import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController";
|
||||
@ -245,6 +248,7 @@ apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
||||
apiRouter.post("/createAlliance.php", createAllianceController);
|
||||
apiRouter.post("/createGuild.php", createGuildController);
|
||||
apiRouter.post("/crewMembers.php", crewMembersController);
|
||||
apiRouter.post("/crewShipFusion.php", crewShipFusionController);
|
||||
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
|
||||
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
||||
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
||||
@ -317,6 +321,7 @@ apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
|
||||
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
|
||||
apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController);
|
||||
apiRouter.post("/setShipVignette.php", setShipVignetteController);
|
||||
apiRouter.post("/setSuitInfection.php", setSuitInfectionController);
|
||||
apiRouter.post("/setWeaponSkillTree.php", setWeaponSkillTreeController);
|
||||
apiRouter.post("/shipDecorations.php", shipDecorationsController);
|
||||
apiRouter.post("/startCollectibleEntry.php", startCollectibleEntryController);
|
||||
@ -327,6 +332,7 @@ apiRouter.post("/syndicateSacrifice.php", syndicateSacrificeController);
|
||||
apiRouter.post("/syndicateStandingBonus.php", syndicateStandingBonusController);
|
||||
apiRouter.post("/tauntHistory.php", tauntHistoryController);
|
||||
apiRouter.post("/trainingResult.php", trainingResultController);
|
||||
apiRouter.post("/umbra.php", umbraController);
|
||||
apiRouter.post("/unlockShipFeature.php", unlockShipFeatureController);
|
||||
apiRouter.post("/updateAlignment.php", updateAlignmentController);
|
||||
apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController);
|
||||
|
@ -2,7 +2,7 @@ import fs from "fs";
|
||||
import path from "path";
|
||||
import { repoDir } from "@/src/helpers/pathHelper";
|
||||
|
||||
interface IConfig {
|
||||
export interface IConfig {
|
||||
mongodbUrl: string;
|
||||
logger: {
|
||||
files: boolean;
|
||||
@ -25,6 +25,10 @@ interface IConfig {
|
||||
infiniteRegalAya?: boolean;
|
||||
infiniteHelminthMaterials?: boolean;
|
||||
claimingBlueprintRefundsIngredients?: boolean;
|
||||
dontSubtractPurchaseCreditCost?: boolean;
|
||||
dontSubtractPurchasePlatinumCost?: boolean;
|
||||
dontSubtractPurchaseItemCost?: boolean;
|
||||
dontSubtractPurchaseStandingCost?: boolean;
|
||||
dontSubtractVoidTraces?: boolean;
|
||||
dontSubtractConsumables?: boolean;
|
||||
unlockAllShipFeatures?: boolean;
|
||||
@ -64,14 +68,16 @@ interface IConfig {
|
||||
starDays?: boolean;
|
||||
eidolonOverride?: string;
|
||||
vallisOverride?: string;
|
||||
duviriOverride?: string;
|
||||
nightwaveOverride?: string;
|
||||
circuitGameModes?: string[];
|
||||
};
|
||||
dev?: {
|
||||
keepVendorsExpired?: boolean;
|
||||
};
|
||||
}
|
||||
|
||||
export const configPath = path.join(repoDir, "config.json");
|
||||
export const configPath = path.join(repoDir, process.argv[2] ?? "config.json");
|
||||
|
||||
export const config: IConfig = {
|
||||
mongodbUrl: "mongodb://127.0.0.1:27017/openWF",
|
||||
|
@ -9,7 +9,7 @@ fs.watchFile(configPath, () => {
|
||||
if (amnesia) {
|
||||
amnesia = false;
|
||||
} else {
|
||||
logger.info("Detected a change to config.json, reloading its contents.");
|
||||
logger.info("Detected a change to config file, reloading its contents.");
|
||||
try {
|
||||
loadConfig();
|
||||
} catch (e) {
|
||||
@ -41,17 +41,11 @@ export const validateConfig = (): void => {
|
||||
}
|
||||
}
|
||||
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();
|
||||
}
|
||||
};
|
||||
|
||||
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> => {
|
||||
amnesia = true;
|
||||
await fsPromises.writeFile(configPath, JSON.stringify(config, null, 2));
|
||||
|
@ -50,14 +50,17 @@ export const createNewEventMessages = async (req: Request): Promise<void> => {
|
||||
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 => ({
|
||||
...m,
|
||||
ownerId: accountId
|
||||
}));
|
||||
|
||||
const savedMessages = await Inbox.insertMany(ownerIdMessages);
|
||||
return savedMessages;
|
||||
return savedMessages as HydratedDocument<IMessageDatabase>[];
|
||||
};
|
||||
|
||||
export interface IMessageCreationTemplate extends Omit<IMessageDatabase, "_id" | "date" | "ownerId"> {
|
||||
|
@ -1580,7 +1580,7 @@ export const addMiscItem = (
|
||||
inventory: TInventoryDatabaseDocument,
|
||||
type: string,
|
||||
count: number,
|
||||
inventoryChanges: IInventoryChanges
|
||||
inventoryChanges: IInventoryChanges = {}
|
||||
): void => {
|
||||
const miscItemChanges: IMiscItem[] = [
|
||||
{
|
||||
@ -1731,12 +1731,27 @@ export const addFocusXpIncreases = (inventory: TInventoryDatabaseDocument, focus
|
||||
AP_ANY
|
||||
}
|
||||
|
||||
inventory.FocusXP ??= { AP_ATTACK: 0, AP_DEFENSE: 0, AP_TACTIC: 0, AP_POWER: 0, AP_WARD: 0 };
|
||||
inventory.FocusXP.AP_ATTACK += focusXpPlus[FocusType.AP_ATTACK];
|
||||
inventory.FocusXP.AP_DEFENSE += focusXpPlus[FocusType.AP_DEFENSE];
|
||||
inventory.FocusXP.AP_TACTIC += focusXpPlus[FocusType.AP_TACTIC];
|
||||
inventory.FocusXP.AP_POWER += focusXpPlus[FocusType.AP_POWER];
|
||||
inventory.FocusXP.AP_WARD += focusXpPlus[FocusType.AP_WARD];
|
||||
inventory.FocusXP ??= {};
|
||||
if (focusXpPlus[FocusType.AP_ATTACK]) {
|
||||
inventory.FocusXP.AP_ATTACK ??= 0;
|
||||
inventory.FocusXP.AP_ATTACK += focusXpPlus[FocusType.AP_ATTACK];
|
||||
}
|
||||
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) {
|
||||
inventory.DailyFocus -= focusXpPlus.reduce((a, b) => a + b, 0);
|
||||
|
@ -67,25 +67,31 @@ export const handlePurchase = async (
|
||||
if (!offer) {
|
||||
throw new Error(`unknown vendor offer: ${ItemId ? ItemId : purchaseRequest.PurchaseParams.StoreItem}`);
|
||||
}
|
||||
if (offer.RegularPrice) {
|
||||
combineInventoryChanges(
|
||||
prePurchaseInventoryChanges,
|
||||
updateCurrency(inventory, offer.RegularPrice[0], false)
|
||||
);
|
||||
if (!config.dontSubtractPurchaseCreditCost) {
|
||||
if (offer.RegularPrice) {
|
||||
combineInventoryChanges(
|
||||
prePurchaseInventoryChanges,
|
||||
updateCurrency(inventory, offer.RegularPrice[0], false)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (offer.PremiumPrice) {
|
||||
combineInventoryChanges(
|
||||
prePurchaseInventoryChanges,
|
||||
updateCurrency(inventory, offer.PremiumPrice[0], true)
|
||||
);
|
||||
if (!config.dontSubtractPurchasePlatinumCost) {
|
||||
if (offer.PremiumPrice) {
|
||||
combineInventoryChanges(
|
||||
prePurchaseInventoryChanges,
|
||||
updateCurrency(inventory, offer.PremiumPrice[0], true)
|
||||
);
|
||||
}
|
||||
}
|
||||
if (offer.ItemPrices) {
|
||||
handleItemPrices(
|
||||
inventory,
|
||||
offer.ItemPrices,
|
||||
purchaseRequest.PurchaseParams.Quantity,
|
||||
prePurchaseInventoryChanges
|
||||
);
|
||||
if (!config.dontSubtractPurchaseItemCost) {
|
||||
if (offer.ItemPrices) {
|
||||
handleItemPrices(
|
||||
inventory,
|
||||
offer.ItemPrices,
|
||||
purchaseRequest.PurchaseParams.Quantity,
|
||||
prePurchaseInventoryChanges
|
||||
);
|
||||
}
|
||||
}
|
||||
if (offer.LocTagRandSeed !== undefined) {
|
||||
seed = BigInt(offer.LocTagRandSeed);
|
||||
@ -179,21 +185,25 @@ export const handlePurchase = async (
|
||||
x => x.ItemType == purchaseRequest.PurchaseParams.StoreItem
|
||||
);
|
||||
if (offer) {
|
||||
combineInventoryChanges(
|
||||
purchaseResponse.InventoryChanges,
|
||||
updateCurrency(inventory, offer.RegularPrice, false)
|
||||
);
|
||||
if (!config.dontSubtractPurchaseCreditCost) {
|
||||
combineInventoryChanges(
|
||||
purchaseResponse.InventoryChanges,
|
||||
updateCurrency(inventory, offer.RegularPrice, false)
|
||||
);
|
||||
}
|
||||
if (purchaseRequest.PurchaseParams.ExpectedPrice) {
|
||||
throw new Error(`vendor purchase should not have an expected price`);
|
||||
}
|
||||
|
||||
const invItem: IMiscItem = {
|
||||
ItemType: "/Lotus/Types/Items/MiscItems/PrimeBucks",
|
||||
ItemCount: offer.PrimePrice * purchaseRequest.PurchaseParams.Quantity * -1
|
||||
};
|
||||
addMiscItems(inventory, [invItem]);
|
||||
purchaseResponse.InventoryChanges.MiscItems ??= [];
|
||||
purchaseResponse.InventoryChanges.MiscItems.push(invItem);
|
||||
if (!config.dontSubtractPurchaseItemCost) {
|
||||
const invItem: IMiscItem = {
|
||||
ItemType: "/Lotus/Types/Items/MiscItems/PrimeBucks",
|
||||
ItemCount: offer.PrimePrice * purchaseRequest.PurchaseParams.Quantity * -1
|
||||
};
|
||||
addMiscItems(inventory, [invItem]);
|
||||
purchaseResponse.InventoryChanges.MiscItems ??= [];
|
||||
purchaseResponse.InventoryChanges.MiscItems.push(invItem);
|
||||
}
|
||||
}
|
||||
break;
|
||||
}
|
||||
@ -211,7 +221,7 @@ export const handlePurchase = async (
|
||||
Title: lastTitle
|
||||
}
|
||||
];
|
||||
} else {
|
||||
} else if (!config.dontSubtractPurchaseStandingCost) {
|
||||
const syndicate = ExportSyndicates[syndicateTag];
|
||||
// eslint-disable-next-line @typescript-eslint/no-unnecessary-condition
|
||||
if (syndicate) {
|
||||
@ -239,19 +249,19 @@ export const handlePurchase = async (
|
||||
const vendor = ExportVendors[purchaseRequest.PurchaseParams.SourceId!];
|
||||
const offer = vendor.items.find(x => x.storeItem == purchaseRequest.PurchaseParams.StoreItem);
|
||||
if (offer) {
|
||||
if (typeof offer.credits == "number") {
|
||||
if (typeof offer.credits == "number" && !config.dontSubtractPurchaseCreditCost) {
|
||||
combineInventoryChanges(
|
||||
purchaseResponse.InventoryChanges,
|
||||
updateCurrency(inventory, offer.credits, false)
|
||||
);
|
||||
}
|
||||
if (typeof offer.platinum == "number") {
|
||||
if (typeof offer.platinum == "number" && !config.dontSubtractPurchasePlatinumCost) {
|
||||
combineInventoryChanges(
|
||||
purchaseResponse.InventoryChanges,
|
||||
updateCurrency(inventory, offer.platinum, true)
|
||||
);
|
||||
}
|
||||
if (offer.itemPrices) {
|
||||
if (offer.itemPrices && !config.dontSubtractPurchaseItemCost) {
|
||||
handleItemPrices(
|
||||
inventory,
|
||||
offer.itemPrices,
|
||||
@ -278,15 +288,17 @@ export const handlePurchase = async (
|
||||
);
|
||||
if (offer) {
|
||||
if (offer.RegularPrice) {
|
||||
const invItem: IMiscItem = {
|
||||
ItemType: "/Lotus/Types/Items/MiscItems/SchismKey",
|
||||
ItemCount: offer.RegularPrice * purchaseRequest.PurchaseParams.Quantity * -1
|
||||
};
|
||||
if (!config.dontSubtractPurchaseItemCost) {
|
||||
const invItem: IMiscItem = {
|
||||
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.push(invItem);
|
||||
purchaseResponse.InventoryChanges.MiscItems ??= [];
|
||||
purchaseResponse.InventoryChanges.MiscItems.push(invItem);
|
||||
}
|
||||
} else if (!config.infiniteRegalAya) {
|
||||
inventory.PrimeTokens -= offer.PrimePrice! * purchaseRequest.PurchaseParams.Quantity;
|
||||
|
||||
|
@ -3,12 +3,10 @@ import { isDev } from "@/src/helpers/pathHelper";
|
||||
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||
import { mixSeeds, SRng } from "@/src/services/rngService";
|
||||
import { IMongoDate } from "@/src/types/commonTypes";
|
||||
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
|
||||
import { logger } from "@/src/utils/logger";
|
||||
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";
|
||||
@ -20,17 +18,12 @@ import DeimosPetVendorManifest from "@/static/fixed_responses/getVendorInfo/Deim
|
||||
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,
|
||||
@ -42,14 +35,10 @@ const rawVendorManifests: IVendorManifest[] = [
|
||||
DuviriAcrithisVendorManifest,
|
||||
EntratiLabsEntratiLabsCommisionsManifest,
|
||||
EntratiLabsEntratiLabVendorManifest,
|
||||
HubsRailjackCrewMemberVendorManifest,
|
||||
MaskSalesmanManifest,
|
||||
Nova1999ConquestShopManifest,
|
||||
OstronPetVendorManifest,
|
||||
SolarisDebtTokenVendorRepossessionsManifest,
|
||||
Temple1999VendorManifest,
|
||||
TeshinHardModeVendorManifest, // uses preprocessing
|
||||
ZarimanCommisionsManifestArchimedean
|
||||
SolarisDebtTokenVendorRepossessionsManifest
|
||||
];
|
||||
|
||||
interface IGeneratableVendorInfo extends Omit<IVendorInfo, "ItemManifest" | "Expiry"> {
|
||||
@ -89,12 +78,16 @@ const gcd = (a: number, b: number): number => {
|
||||
const getCycleDuration = (manifest: IVendor): number => {
|
||||
let dur = 0;
|
||||
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;
|
||||
break;
|
||||
}
|
||||
if (dur != item.durationHours) {
|
||||
dur = gcd(dur, item.durationHours);
|
||||
if (dur != durationHours) {
|
||||
dur = gcd(dur, durationHours);
|
||||
}
|
||||
}
|
||||
return dur * unixTimesInMs.hour;
|
||||
@ -103,7 +96,7 @@ const getCycleDuration = (manifest: IVendor): number => {
|
||||
export const getVendorManifestByTypeName = (typeName: string): IVendorManifest | undefined => {
|
||||
for (const vendorManifest of rawVendorManifests) {
|
||||
if (vendorManifest.VendorInfo.TypeName == typeName) {
|
||||
return preprocessVendorManifest(vendorManifest);
|
||||
return vendorManifest;
|
||||
}
|
||||
}
|
||||
for (const vendorInfo of generatableVendors) {
|
||||
@ -126,7 +119,7 @@ export const getVendorManifestByTypeName = (typeName: string): IVendorManifest |
|
||||
export const getVendorManifestByOid = (oid: string): IVendorManifest | undefined => {
|
||||
for (const vendorManifest of rawVendorManifests) {
|
||||
if (vendorManifest.VendorInfo._id.$oid == oid) {
|
||||
return preprocessVendorManifest(vendorManifest);
|
||||
return vendorManifest;
|
||||
}
|
||||
}
|
||||
for (const vendorInfo of generatableVendors) {
|
||||
@ -185,30 +178,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 => {
|
||||
if (typeof value == "number") {
|
||||
return { minValue: value, maxValue: value };
|
||||
@ -232,6 +201,18 @@ const getCycleDurationRange = (manifest: IVendor): IRange | 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 generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifest => {
|
||||
@ -272,47 +253,69 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
||||
const rng = new SRng(mixSeeds(vendorSeed, cycleIndex));
|
||||
const offersToAdd: IVendorOffer[] = [];
|
||||
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) {
|
||||
remainingItemCapacity[item.storeItem] = 1 + item.duplicates;
|
||||
remainingItemCapacity[getOfferId(item)] = 1 + item.duplicates;
|
||||
}
|
||||
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);
|
||||
while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) {
|
||||
// TODO: Consider per-bin item limits
|
||||
// TODO: Consider item probability weightings
|
||||
const item = rng.randomElement(manifest.items)!;
|
||||
if (remainingItemCapacity[item.storeItem] != 0) {
|
||||
remainingItemCapacity[item.storeItem] -= 1;
|
||||
|
||||
// Add permanent offers
|
||||
let numUncountedOffers = 0;
|
||||
let offset = 0;
|
||||
for (const item of manifest.items) {
|
||||
if (item.alwaysOffered || item.rotatedWeekly) {
|
||||
++numUncountedOffers;
|
||||
const id = getOfferId(item);
|
||||
if (remainingItemCapacity[id] != 0) {
|
||||
remainingItemCapacity[id] -= 1;
|
||||
offersToAdd.push(item);
|
||||
++offset;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
for (const item of manifest.items) {
|
||||
if (!item.alwaysOffered && remainingItemCapacity[item.storeItem] != 0) {
|
||||
remainingItemCapacity[item.storeItem] -= 1;
|
||||
offersToAdd.push(item);
|
||||
}
|
||||
|
||||
// Add counted offers
|
||||
const useRng = manifest.numItems && manifest.numItems.minValue != manifest.numItems.maxValue;
|
||||
const numItemsTarget = manifest.numItems
|
||||
? numUncountedOffers +
|
||||
(useRng
|
||||
? rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue)
|
||||
: manifest.numItems.minValue)
|
||||
: manifest.items.length;
|
||||
let i = 0;
|
||||
while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) {
|
||||
const item = useRng ? rng.randomElement(manifest.items)! : manifest.items[i++];
|
||||
if (
|
||||
!item.alwaysOffered &&
|
||||
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)) {
|
||||
const item = manifest.items.find(x => x.storeItem == e[0])!;
|
||||
if (!item.alwaysOffered) {
|
||||
while (e[1] != 0) {
|
||||
e[1] -= 1;
|
||||
offersToAdd.push(item);
|
||||
}
|
||||
}
|
||||
if (i == manifest.items.length) {
|
||||
i = 0;
|
||||
}
|
||||
for (const item of manifest.items) {
|
||||
if (item.alwaysOffered && remainingItemCapacity[item.storeItem] != 0) {
|
||||
remainingItemCapacity[item.storeItem] -= 1;
|
||||
offersToAdd.push(item);
|
||||
}
|
||||
}
|
||||
offersToAdd.reverse();
|
||||
}
|
||||
} else {
|
||||
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 +328,21 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
||||
const cycleStart = cycleOffset + cycleIndex * cycleDuration;
|
||||
for (const rawItem of offersToAdd) {
|
||||
const durationHoursRange = toRange(rawItem.durationHours ?? cycleDuration);
|
||||
const expiry =
|
||||
cycleStart +
|
||||
rng.randomInt(durationHoursRange.minValue, durationHoursRange.maxValue) * unixTimesInMs.hour;
|
||||
const expiry = rawItem.alwaysOffered
|
||||
? 2051240400_000
|
||||
: cycleStart +
|
||||
(rawItem.rotatedWeekly
|
||||
? unixTimesInMs.week
|
||||
: rng.randomInt(durationHoursRange.minValue, durationHoursRange.maxValue) * unixTimesInMs.hour);
|
||||
const item: IItemManifest = {
|
||||
StoreItem: rawItem.storeItem,
|
||||
ItemPrices: rawItem.itemPrices?.map(itemPrice => ({ ...itemPrice, ProductCategory: "MiscItems" })),
|
||||
Bin: "BIN_" + rawItem.bin,
|
||||
QuantityMultiplier: rawItem.quantity,
|
||||
Expiry: { $date: { $numberLong: expiry.toString() } },
|
||||
AllowMultipurchase: false,
|
||||
PurchaseQuantityLimit: rawItem.purchaseLimit,
|
||||
RotatedWeekly: rawItem.rotatedWeekly,
|
||||
AllowMultipurchase: rawItem.purchaseLimit !== 1,
|
||||
Id: {
|
||||
$oid:
|
||||
((cycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") +
|
||||
@ -383,6 +391,12 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
||||
info.ItemManifest.push(item);
|
||||
}
|
||||
|
||||
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
|
||||
let soonestOfferExpiry: number = Number.MAX_SAFE_INTEGER;
|
||||
for (const offer of info.ItemManifest) {
|
||||
@ -399,6 +413,13 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
||||
};
|
||||
|
||||
if (isDev) {
|
||||
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")!
|
||||
.VendorInfo.ItemManifest;
|
||||
if (
|
||||
@ -424,4 +445,23 @@ if (isDev) {
|
||||
) {
|
||||
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`);
|
||||
}
|
||||
}
|
||||
|
@ -16,7 +16,10 @@ import {
|
||||
ISortie,
|
||||
ISortieMission,
|
||||
ISyndicateMissionInfo,
|
||||
IWorldState
|
||||
ITmp,
|
||||
IVoidStorm,
|
||||
IWorldState,
|
||||
TCircuitGameMode
|
||||
} from "../types/worldStateTypes";
|
||||
import { version_compare } from "../helpers/inventoryHelpers";
|
||||
import { logger } from "../utils/logger";
|
||||
@ -963,6 +966,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 => {
|
||||
if (config.worldState?.eidolonOverride) {
|
||||
const eidolonEpoch = 1391992660;
|
||||
@ -1010,6 +1068,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;
|
||||
};
|
||||
|
||||
@ -1032,6 +1111,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
Sorties: [],
|
||||
LiteSorties: [],
|
||||
GlobalUpgrades: [],
|
||||
VoidStorms: [],
|
||||
EndlessXpChoices: [],
|
||||
KnownCalendarSeasons: [],
|
||||
...staticWorldState,
|
||||
@ -1228,12 +1308,27 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
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 tmp = {
|
||||
const hourInSeconds = 3600;
|
||||
const cheeseInterval = hourInSeconds * 8;
|
||||
const cheeseDuration = hourInSeconds * 2;
|
||||
const cheeseIndex = Math.trunc(timeSecs / cheeseInterval);
|
||||
const tmp: ITmp = {
|
||||
cavabegin: "1690761600",
|
||||
PurchasePlatformLockEnabled: true,
|
||||
tcsn: true,
|
||||
pgr: {
|
||||
ts: "1732572900",
|
||||
en: "CUSTOM DECALS @ ZEVILA",
|
||||
@ -1254,8 +1349,16 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||
},
|
||||
ennnd: 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]
|
||||
};
|
||||
if (Array.isArray(config.worldState?.circuitGameModes)) {
|
||||
tmp.edg = config.worldState.circuitGameModes as TCircuitGameMode[];
|
||||
}
|
||||
worldState.Tmp = JSON.stringify(tmp);
|
||||
|
||||
return worldState;
|
||||
|
@ -234,7 +234,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
||||
HandlerPoints: number;
|
||||
MiscItems: IMiscItem[];
|
||||
HasOwnedVoidProjectionsPreviously?: boolean;
|
||||
ChallengesFixVersion: number;
|
||||
ChallengesFixVersion?: number;
|
||||
ChallengeProgress: IChallengeProgress[];
|
||||
RawUpgrades: IRawUpgrade[];
|
||||
ReceivedStartingGear: boolean;
|
||||
@ -641,11 +641,11 @@ export interface IFocusUpgrade {
|
||||
}
|
||||
|
||||
export interface IFocusXP {
|
||||
AP_POWER: number;
|
||||
AP_TACTIC: number;
|
||||
AP_DEFENSE: number;
|
||||
AP_ATTACK: number;
|
||||
AP_WARD: number;
|
||||
AP_POWER?: number;
|
||||
AP_TACTIC?: number;
|
||||
AP_DEFENSE?: number;
|
||||
AP_ATTACK?: number;
|
||||
AP_WARD?: number;
|
||||
}
|
||||
|
||||
export type TFocusPolarity = keyof IFocusXP;
|
||||
|
@ -12,6 +12,7 @@ export interface IWorldState {
|
||||
GlobalUpgrades: IGlobalUpgrade[];
|
||||
ActiveMissions: IFissure[];
|
||||
NodeOverrides: INodeOverride[];
|
||||
VoidStorms: IVoidStorm[];
|
||||
PVPChallengeInstances: IPVPChallengeInstance[];
|
||||
EndlessXpChoices: IEndlessXpChoice[];
|
||||
SeasonInfo?: {
|
||||
@ -131,6 +132,14 @@ export interface ILiteSortie {
|
||||
}[];
|
||||
}
|
||||
|
||||
export interface IVoidStorm {
|
||||
_id: IOid;
|
||||
Node: string;
|
||||
Activation: IMongoDate;
|
||||
Expiry: IMongoDate;
|
||||
ActiveMissionTier: string;
|
||||
}
|
||||
|
||||
export interface IPVPChallengeInstance {
|
||||
_id: IOid;
|
||||
challengeTypeRefID: string;
|
||||
@ -182,3 +191,48 @@ export interface ICalendarEvent {
|
||||
dialogueName?: 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;
|
||||
}
|
||||
|
@ -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" } }
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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"
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
@ -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" } }
|
||||
}
|
||||
}
|
@ -2562,50 +2562,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" },
|
||||
"PrimeVaultAvailabilities": [false, false, false, false, false],
|
||||
"PrimeTokenAvailability": true,
|
||||
|
@ -571,7 +571,7 @@
|
||||
<div id="server-settings-no-perms" class="d-none">
|
||||
<p class="card-text" data-loc="cheats_administratorRequirement"></p>
|
||||
</div>
|
||||
<form id="server-settings" class="d-none" onsubmit="doChangeSettings();return false;">
|
||||
<div id="server-settings" class="d-none">
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="skipTutorial" />
|
||||
<label class="form-check-label" for="skipTutorial" data-loc="cheats_skipTutorial"></label>
|
||||
@ -604,13 +604,29 @@
|
||||
<input class="form-check-input" type="checkbox" id="infiniteRegalAya" />
|
||||
<label class="form-check-label" for="infiniteRegalAya" data-loc="cheats_infiniteRegalAya"></label>
|
||||
</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">
|
||||
<input class="form-check-input" type="checkbox" id="claimingBlueprintRefundsIngredients" />
|
||||
<label class="form-check-label" for="claimingBlueprintRefundsIngredients" data-loc="cheats_claimingBlueprintRefundsIngredients"></label>
|
||||
</div>
|
||||
<div class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="infiniteHelminthMaterials" />
|
||||
<label class="form-check-label" for="infiniteHelminthMaterials" data-loc="cheats_infiniteHelminthMaterials"></label>
|
||||
<input class="form-check-input" type="checkbox" id="dontSubtractPurchaseCreditCost" />
|
||||
<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 class="form-check">
|
||||
<input class="form-check-input" type="checkbox" id="dontSubtractVoidTraces" />
|
||||
@ -732,16 +748,21 @@
|
||||
<input class="form-check-input" type="checkbox" id="fastClanAscension" />
|
||||
<label class="form-check-label" for="fastClanAscension" data-loc="cheats_fastClanAscension"></label>
|
||||
</div>
|
||||
<div class="form-group mt-2">
|
||||
<form class="form-group mt-2" onsubmit="doSaveConfig('spoofMasteryRank'); return false;">
|
||||
<label class="form-label" for="spoofMasteryRank" data-loc="cheats_spoofMasteryRank"></label>
|
||||
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" max="65535" />
|
||||
</div>
|
||||
<div class="form-group mt-2">
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" max="65535" />
|
||||
<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>
|
||||
<input class="form-control" id="nightwaveStandingMultiplier" type="number" min="1" max="1000000" value="1" />
|
||||
</div>
|
||||
<button class="btn btn-primary mt-3" type="submit" data-loc="cheats_saveSettings"></button>
|
||||
</form>
|
||||
<div class="input-group">
|
||||
<input class="form-control" id="nightwaveStandingMultiplier" type="number" min="1" max="1000000" value="1" />
|
||||
<button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
|
||||
</div>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -29,7 +29,7 @@ function loginFromLocalStorage() {
|
||||
},
|
||||
() => {
|
||||
logout();
|
||||
alert(isRegister ? "Registration failed. Account already exists?" : "Login failed");
|
||||
alert(loc(isRegister ? "code_regFail" : "code_loginFail"));
|
||||
}
|
||||
);
|
||||
}
|
||||
@ -546,6 +546,9 @@ function updateInventory() {
|
||||
td.textContent = item.ItemName + " (" + td.textContent + ")";
|
||||
}
|
||||
}
|
||||
if (item.Details?.Name) {
|
||||
td.textContent = item.Details.Name + " (" + td.textContent + ")";
|
||||
}
|
||||
if (item.ModularParts && item.ModularParts.length) {
|
||||
td.textContent += " [";
|
||||
item.ModularParts.forEach(part => {
|
||||
@ -1506,15 +1509,28 @@ function sendBatchGearExp(data) {
|
||||
|
||||
function renameGear(category, oid, name) {
|
||||
revalidateAuthz(() => {
|
||||
$.post({
|
||||
url: "/api/nameWeapon.php?" + window.authz + "&Category=" + category + "&ItemId=" + oid + "&webui=1",
|
||||
contentType: "text/plain",
|
||||
data: JSON.stringify({
|
||||
ItemName: name
|
||||
})
|
||||
}).done(function () {
|
||||
updateInventory();
|
||||
});
|
||||
if (category == "KubrowPets") {
|
||||
$.post({
|
||||
url: "/api/renamePet.php?" + window.authz + "&webui=1",
|
||||
contentType: "text/plain",
|
||||
data: JSON.stringify({
|
||||
petId: oid,
|
||||
name: name
|
||||
})
|
||||
}).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();
|
||||
});
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
@ -1761,34 +1777,29 @@ function doAcquireMod() {
|
||||
|
||||
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
|
||||
|
||||
function doChangeSettings() {
|
||||
revalidateAuthz(() => {
|
||||
fetch("/custom/config?" + window.authz)
|
||||
.then(response => response.json())
|
||||
.then(json => {
|
||||
for (const i of uiConfigs) {
|
||||
var x = document.getElementById(i);
|
||||
if (x != null) {
|
||||
if (x.type == "checkbox") {
|
||||
if (x.checked === true) {
|
||||
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
|
||||
for (const id of uiConfigs) {
|
||||
const elm = document.getElementById(id);
|
||||
if (elm.type == "checkbox") {
|
||||
elm.onchange = function () {
|
||||
$.post({
|
||||
url: "/custom/config?" + window.authz,
|
||||
contentType: "application/json",
|
||||
data: JSON.stringify({ key: id, value: this.checked })
|
||||
}).then(() => {
|
||||
if (["infiniteCredits", "infinitePlatinum", "infiniteEndo", "infiniteRegalAya"].indexOf(id) != -1) {
|
||||
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) })
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -3,6 +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_addButton: `Hinzufügen`,
|
||||
general_bulkActions: `Massenaktionen`,
|
||||
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
||||
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
|
||||
code_nonValidAuthz: `Deine Anmeldedaten sind nicht mehr gültig.`,
|
||||
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.`,
|
||||
@ -133,11 +135,15 @@ dict = {
|
||||
cheats_infiniteRegalAya: `Unendlich Reines Aya`,
|
||||
cheats_infiniteHelminthMaterials: `Unendlich Helminth-Materialien`,
|
||||
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_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`,
|
||||
cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen 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_unlockAllCapturaScenes: `Alle Photora-Szenen freischalten`,
|
||||
cheats_unlockAllDecoRecipes: `Alle Dojo-Deko-Baupläne freischalten`,
|
||||
@ -165,7 +171,7 @@ dict = {
|
||||
cheats_fastClanAscension: `Schneller Clan-Aufstieg`,
|
||||
cheats_spoofMasteryRank: `Gefälschter Meisterschaftsrang (-1 zum deaktivieren)`,
|
||||
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
|
||||
cheats_saveSettings: `Einstellungen speichern`,
|
||||
cheats_save: `[UNTRANSLATED] Save`,
|
||||
cheats_account: `Account`,
|
||||
cheats_unlockAllFocusSchools: `Alle Fokus-Schulen freischalten`,
|
||||
cheats_helminthUnlockAll: `Helminth vollständig aufleveln`,
|
||||
@ -183,7 +189,7 @@ dict = {
|
||||
upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`,
|
||||
upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`,
|
||||
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_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`,
|
||||
upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`,
|
||||
|
@ -2,6 +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_addButton: `Add`,
|
||||
general_bulkActions: `Bulk Actions`,
|
||||
code_loginFail: `Login failed. Double-check the email and password.`,
|
||||
code_regFail: `Registration failed. Account already exists?`,
|
||||
code_nonValidAuthz: `Your credentials are no longer valid.`,
|
||||
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.`,
|
||||
@ -132,11 +134,15 @@ dict = {
|
||||
cheats_infiniteRegalAya: `Infinite Regal Aya`,
|
||||
cheats_infiniteHelminthMaterials: `Infinite Helminth Materials`,
|
||||
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_dontSubtractConsumables: `Don't Subtract Consumables`,
|
||||
cheats_unlockAllShipFeatures: `Unlock All Ship Features`,
|
||||
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_unlockAllCapturaScenes: `Unlock All Captura Scenes`,
|
||||
cheats_unlockAllDecoRecipes: `Unlock All Dojo Deco Recipes`,
|
||||
@ -164,7 +170,7 @@ dict = {
|
||||
cheats_fastClanAscension: `Fast Clan Ascension`,
|
||||
cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`,
|
||||
cheats_nightwaveStandingMultiplier: `Nightwave Standing Multiplier`,
|
||||
cheats_saveSettings: `Save Settings`,
|
||||
cheats_save: `Save`,
|
||||
cheats_account: `Account`,
|
||||
cheats_unlockAllFocusSchools: `Unlock All Focus Schools`,
|
||||
cheats_helminthUnlockAll: `Fully Level Up Helminth`,
|
||||
@ -182,7 +188,7 @@ dict = {
|
||||
upgrade_WarframeAbilityDuration: `+|VAL|% Ability Duration`,
|
||||
upgrade_WarframeAbilityStrength: `+|VAL|% Ability Strength`,
|
||||
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_WarframeCorrosiveDamageBoost: `+|VAL|% Ability Damage on enemies affected by Corrosion Status`,
|
||||
upgrade_WarframeCorrosiveStack: `Increase max stacks of Corrosion Status by +|VAL|`,
|
||||
|
@ -3,6 +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_addButton: `Agregar`,
|
||||
general_bulkActions: `Acciones masivas`,
|
||||
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_nonValidAuthz: `Tus credenciales no son válidas.`,
|
||||
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.`,
|
||||
@ -133,6 +135,10 @@ dict = {
|
||||
cheats_infiniteRegalAya: `Aya Real infinita`,
|
||||
cheats_infiniteHelminthMaterials: `Materiales Helminto infinitos`,
|
||||
cheats_claimingBlueprintRefundsIngredients: `Reclamar ingredientes devueltos por planos`,
|
||||
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: `No descontar vestigios del Vacío`,
|
||||
cheats_dontSubtractConsumables: `No restar consumibles`,
|
||||
cheats_unlockAllShipFeatures: `Desbloquear todas las funciones de nave`,
|
||||
@ -165,7 +171,7 @@ dict = {
|
||||
cheats_fastClanAscension: `Ascenso rápido del clan`,
|
||||
cheats_spoofMasteryRank: `Rango de maestría simulado (-1 para desactivar)`,
|
||||
cheats_nightwaveStandingMultiplier: `Multiplicador de Reputación de Onda Nocturna`,
|
||||
cheats_saveSettings: `Guardar configuración`,
|
||||
cheats_save: `Guardar`,
|
||||
cheats_account: `Cuenta`,
|
||||
cheats_unlockAllFocusSchools: `Desbloquear todas las escuelas de enfoque`,
|
||||
cheats_helminthUnlockAll: `Subir al máximo el Helminto`,
|
||||
@ -183,7 +189,7 @@ dict = {
|
||||
upgrade_WarframeAbilityDuration: `+|VAL|% de duración de habilidades`,
|
||||
upgrade_WarframeAbilityStrength: `+|VAL|% de fuerza de habilidades`,
|
||||
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_WarframeCorrosiveDamageBoost: `+|VAL|% de daño de habilidades a enemigos con estado corrosivo`,
|
||||
upgrade_WarframeCorrosiveStack: `Aumenta los acumuladores máximos de estado corrosivo en +|VAL|`,
|
||||
|
@ -3,6 +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_addButton: `Ajouter`,
|
||||
general_bulkActions: `Action groupée`,
|
||||
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
||||
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
|
||||
code_nonValidAuthz: `Informations de connexion invalides`,
|
||||
code_changeNameConfirm: `Nouveau nom du compte :`,
|
||||
code_deleteAccountConfirm: `Supprimer |DISPLAYNAME| (|EMAIL|) ? Cette action est irreversible.`,
|
||||
@ -133,11 +135,15 @@ dict = {
|
||||
cheats_infiniteRegalAya: `Aya Raffiné infini`,
|
||||
cheats_infiniteHelminthMaterials: `Ressources d'Helminth infinies`,
|
||||
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_dontSubtractConsumables: `Ne pas retirer de consommables`,
|
||||
cheats_unlockAllShipFeatures: `Débloquer tous les segments 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_unlockAllCapturaScenes: `Débloquer toutes les scènes captura`,
|
||||
cheats_unlockAllDecoRecipes: `Débloquer toutes les recherches dojo`,
|
||||
@ -165,7 +171,7 @@ dict = {
|
||||
cheats_fastClanAscension: `Ascension de clan rapide`,
|
||||
cheats_spoofMasteryRank: `Rang de maîtrise personnalisé (-1 pour désactiver)`,
|
||||
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
|
||||
cheats_saveSettings: `Sauvegarder les paramètres`,
|
||||
cheats_save: `[UNTRANSLATED] Save`,
|
||||
cheats_account: `Compte`,
|
||||
cheats_unlockAllFocusSchools: `Débloquer toutes les écoles de focus`,
|
||||
cheats_helminthUnlockAll: `Helminth niveau max`,
|
||||
@ -183,7 +189,7 @@ dict = {
|
||||
upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`,
|
||||
upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`,
|
||||
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_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`,
|
||||
upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`,
|
||||
|
@ -3,6 +3,8 @@ dict = {
|
||||
general_inventoryUpdateNote: `Примечание: изменения, внесенные здесь, отобразятся в игре только после повторной загрузки вашего инвентаря. Посещение навигации — самый простой способ этого добиться.`,
|
||||
general_addButton: `Добавить`,
|
||||
general_bulkActions: `Массовые действия`,
|
||||
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
||||
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
|
||||
code_nonValidAuthz: `Ваши данные больше не действительны.`,
|
||||
code_changeNameConfirm: `Какое имя вы хотите установить для своей учетной записи?`,
|
||||
code_deleteAccountConfirm: `Вы уверены, что хотите удалить аккаунт |DISPLAYNAME| (|EMAIL|)? Это действие нельзя отменить.`,
|
||||
@ -133,11 +135,15 @@ dict = {
|
||||
cheats_infiniteRegalAya: `Бесконечная Королевская Айя`,
|
||||
cheats_infiniteHelminthMaterials: `Бесконечные Выделения Гельминта`,
|
||||
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_dontSubtractConsumables: `Не уменьшать количество расходников`,
|
||||
cheats_unlockAllShipFeatures: `Разблокировать все функции корабля`,
|
||||
cheats_unlockAllShipDecorations: `Разблокировать все украшения корабля`,
|
||||
cheats_unlockAllFlavourItems: `Разблокировать все <abbr title=\"Наборы анимаций, глифы, палитры и т. д.\">уникальные предметы</abbr>`,
|
||||
cheats_unlockAllFlavourItems: `Разблокировать все <abbr title="Наборы анимаций, глифы, палитры и т. д.">уникальные предметы</abbr>`,
|
||||
cheats_unlockAllSkins: `Разблокировать все скины`,
|
||||
cheats_unlockAllCapturaScenes: `Разблокировать все сцены Каптуры`,
|
||||
cheats_unlockAllDecoRecipes: `Разблокировать все рецепты декораций Дoдзё`,
|
||||
@ -165,7 +171,7 @@ dict = {
|
||||
cheats_fastClanAscension: `Мгновенное Вознесение Клана`,
|
||||
cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`,
|
||||
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
|
||||
cheats_saveSettings: `Сохранить настройки`,
|
||||
cheats_save: `[UNTRANSLATED] Save`,
|
||||
cheats_account: `Аккаунт`,
|
||||
cheats_unlockAllFocusSchools: `Разблокировать все школы фокуса`,
|
||||
cheats_helminthUnlockAll: `Полностью улучшить Гельминта`,
|
||||
@ -183,7 +189,7 @@ dict = {
|
||||
upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`,
|
||||
upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`,
|
||||
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_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`,
|
||||
upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`,
|
||||
|
@ -3,6 +3,8 @@ dict = {
|
||||
general_inventoryUpdateNote: `注意:此处所做的更改只有在游戏同步仓库后才会生效。您可以通过访问星图来触发仓库更新。`,
|
||||
general_addButton: `添加`,
|
||||
general_bulkActions: `批量操作`,
|
||||
code_loginFail: `登录失败。请检查邮箱和密码。`,
|
||||
code_regFail: `注册失败。账号已存在。`,
|
||||
code_nonValidAuthz: `您的登录凭证已失效。`,
|
||||
code_changeNameConfirm: `您想将账户名称更改为什么?`,
|
||||
code_deleteAccountConfirm: `确定要删除账户 |DISPLAYNAME| (|EMAIL|) 吗?此操作不可撤销。`,
|
||||
@ -25,7 +27,7 @@ dict = {
|
||||
code_renamePrompt: `输入新的自定义名称:`,
|
||||
code_remove: `移除`,
|
||||
code_addItemsConfirm: `确定要向账户添加 |COUNT| 件物品吗?`,
|
||||
code_succRankUp: `[UNTRANSLATED] Successfully ranked up.`,
|
||||
code_succRankUp: `等级已提升`,
|
||||
code_noEquipmentToRankUp: `没有可升级的装备。`,
|
||||
code_succAdded: `已成功添加。`,
|
||||
code_succRemoved: `已成功移除。`,
|
||||
@ -34,8 +36,8 @@ dict = {
|
||||
code_rerollsNumber: `洗卡次数`,
|
||||
code_viewStats: `查看属性`,
|
||||
code_rank: `等级`,
|
||||
code_rankUp: `[UNTRANSLATED] Rank up`,
|
||||
code_rankDown: `[UNTRANSLATED] Rank down`,
|
||||
code_rankUp: `等级提升`,
|
||||
code_rankDown: `等级下降`,
|
||||
code_count: `数量`,
|
||||
code_focusAllUnlocked: `所有专精学派均已解锁。`,
|
||||
code_focusUnlocked: `已解锁 |COUNT| 个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新。`,
|
||||
@ -133,11 +135,15 @@ dict = {
|
||||
cheats_infiniteRegalAya: `无限御品阿耶`,
|
||||
cheats_infiniteHelminthMaterials: `无限Helminth材料`,
|
||||
cheats_claimingBlueprintRefundsIngredients: `取消蓝图制造时返还材料`,
|
||||
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: `虚空光体无消耗`,
|
||||
cheats_dontSubtractConsumables: `消耗物品使用时无损耗`,
|
||||
cheats_unlockAllShipFeatures: `解锁所有飞船功能`,
|
||||
cheats_unlockAllShipDecorations: `解锁所有飞船装饰`,
|
||||
cheats_unlockAllFlavourItems: `解锁所有<abbr title=\"动画组合、图标、调色板等\">装饰物品</abbr>`,
|
||||
cheats_unlockAllFlavourItems: `解锁所有<abbr title="动画组合、图标、调色板等">装饰物品</abbr>`,
|
||||
cheats_unlockAllSkins: `解锁所有外观`,
|
||||
cheats_unlockAllCapturaScenes: `解锁所有Captura场景`,
|
||||
cheats_unlockAllDecoRecipes: `解锁所有道场配方`,
|
||||
@ -165,7 +171,7 @@ dict = {
|
||||
cheats_fastClanAscension: `快速升级氏族`,
|
||||
cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`,
|
||||
cheats_nightwaveStandingMultiplier: `午夜电波声望倍率`,
|
||||
cheats_saveSettings: `保存设置`,
|
||||
cheats_save: `[UNTRANSLATED] Save`,
|
||||
cheats_account: `账户`,
|
||||
cheats_unlockAllFocusSchools: `解锁所有专精学派`,
|
||||
cheats_helminthUnlockAll: `完全升级Helminth`,
|
||||
@ -176,56 +182,56 @@ dict = {
|
||||
import_importNote: `您可以在此处提供完整或部分库存响应(客户端表示)。支持的所有字段<b>将被覆盖</b>到您的账户中。`,
|
||||
import_submit: `提交`,
|
||||
|
||||
upgrade_Equilibrium: `[UNTRANSLATED] +|VAL|% Energy from Health pickups, +|VAL|% Health from Energy pickups`,
|
||||
upgrade_MeleeCritDamage: `[UNTRANSLATED] +|VAL|% Melee Critical Damage`,
|
||||
upgrade_PrimaryStatusChance: `[UNTRANSLATED] +|VAL|% Primary Status Chance`,
|
||||
upgrade_SecondaryCritChance: `[UNTRANSLATED] +|VAL|% Secondary Critical Chance`,
|
||||
upgrade_WarframeAbilityDuration: `[UNTRANSLATED] +|VAL|% Ability Duration`,
|
||||
upgrade_WarframeAbilityStrength: `[UNTRANSLATED] +|VAL|% Ability Strength`,
|
||||
upgrade_WarframeArmourMax: `[UNTRANSLATED] +|VAL| Armor`,
|
||||
upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on inflicting Blast Status`,
|
||||
upgrade_WarframeCastingSpeed: `[UNTRANSLATED] +|VAL|% Casting Speed`,
|
||||
upgrade_WarframeCorrosiveDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Corrosion Status`,
|
||||
upgrade_WarframeCorrosiveStack: `[UNTRANSLATED] Increase max stacks of Corrosion Status by +|VAL|`,
|
||||
upgrade_WarframeCritDamageBoost: `[UNTRANSLATED] +|VAL|% Melee Critical Damage (Doubles over 500 Energy)`,
|
||||
upgrade_WarframeElectricDamage: `[UNTRANSLATED] +|VAL1|% Primary Electricity Damage (+|VAL2|% per additional Shard)`,
|
||||
upgrade_WarframeElectricDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Electricity Status`,
|
||||
upgrade_WarframeEnergyMax: `[UNTRANSLATED] +|VAL| Energy Max`,
|
||||
upgrade_WarframeGlobeEffectEnergy: `[UNTRANSLATED] +|VAL|% Energy Orb Effectiveness`,
|
||||
upgrade_WarframeGlobeEffectHealth: `[UNTRANSLATED] +|VAL|% Health Orb Effectiveness`,
|
||||
upgrade_WarframeHealthMax: `[UNTRANSLATED] +|VAL| Health`,
|
||||
upgrade_WarframeHPBoostFromImpact: `[UNTRANSLATED] +|VAL1| Health per enemy killed with Blast Damage (Max |VAL2| Health)`,
|
||||
upgrade_WarframeParkourVelocity: `[UNTRANSLATED] +|VAL|% Parkour Velocity`,
|
||||
upgrade_WarframeRadiationDamageBoost: `[UNTRANSLATED] +|VAL|% Ability Damage on enemies affected by Radiation Status`,
|
||||
upgrade_WarframeRegen: `[UNTRANSLATED] +|VAL| Health Regen/s`,
|
||||
upgrade_WarframeShieldMax: `[UNTRANSLATED] +|VAL| Shield`,
|
||||
upgrade_WarframeStartingEnergy: `[UNTRANSLATED] +|VAL|% Energy on Spawn`,
|
||||
upgrade_WarframeToxinDamage: `[UNTRANSLATED] +|VAL|% Toxin Status Effect Damage`,
|
||||
upgrade_WarframeToxinHeal: `[UNTRANSLATED] +|VAL| Health on damaging enemies with Toxin Status`,
|
||||
upgrade_WeaponCritBoostFromHeat: `[UNTRANSLATED] +|VAL1|% Secondary Critical Chance per Heat-affected enemy killed (Max |VAL2|%)`,
|
||||
upgrade_AvatarAbilityRange: `[UNTRANSLATED] +7.5% Ability Range`,
|
||||
upgrade_AvatarAbilityEfficiency: `[UNTRANSLATED] +5% Ability Efficiency`,
|
||||
upgrade_AvatarEnergyRegen: `[UNTRANSLATED] +0.5 Energy Regen/s`,
|
||||
upgrade_AvatarEnemyRadar: `[UNTRANSLATED] +5m Enemy Radar`,
|
||||
upgrade_AvatarLootRadar: `[UNTRANSLATED] +7m Loot Radar`,
|
||||
upgrade_WeaponAmmoMax: `[UNTRANSLATED] +15% Ammo Max`,
|
||||
upgrade_EnemyArmorReductionAura: `[UNTRANSLATED] -3% Enemy Armor`,
|
||||
upgrade_OnExecutionAmmo: `[UNTRANSLATED] 100% Primary and Secondary Magazine Refill on Mercy`,
|
||||
upgrade_OnExecutionHealthDrop: `[UNTRANSLATED] 100% chance to drop a Health Orb on Mercy`,
|
||||
upgrade_OnExecutionEnergyDrop: `[UNTRANSLATED] 50% chance to drop an Energy Orb on Mercy`,
|
||||
upgrade_OnFailHackReset: `[UNTRANSLATED] +50% to retry on Hacking failure`,
|
||||
upgrade_DamageReductionOnHack: `[UNTRANSLATED] 75% Damage Reduction while Hacking`,
|
||||
upgrade_OnExecutionReviveCompanion: `[UNTRANSLATED] Mercy Kills reduce Companion Recovery by 15s`,
|
||||
upgrade_OnExecutionParkourSpeed: `[UNTRANSLATED] +60% Parkour Speed after a Mercy for 15s`,
|
||||
upgrade_AvatarTimeLimitIncrease: `[UNTRANSLATED] s to Hacking`,
|
||||
upgrade_ElectrifyOnHack: `[UNTRANSLATED] Shock enemies within 20m while Hacking`,
|
||||
upgrade_OnExecutionTerrify: `[UNTRANSLATED] 50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`,
|
||||
upgrade_OnHackLockers: `[UNTRANSLATED] Unlock 5 lockers within 20m after Hacking`,
|
||||
upgrade_OnExecutionBlind: `[UNTRANSLATED] Blind enemies within 18m on Mercy`,
|
||||
upgrade_OnExecutionDrainPower: `[UNTRANSLATED] 100% chance for next ability cast to gain +50% Ability Strength on Mercy`,
|
||||
upgrade_OnHackSprintSpeed: `[UNTRANSLATED] +75% Sprint Speed for 15s after Hacking`,
|
||||
upgrade_SwiftExecute: `[UNTRANSLATED] Speed of Mercy Kills increased by 50%`,
|
||||
upgrade_OnHackInvis: `[UNTRANSLATED] Invisible for 15 seconds after hacking`,
|
||||
upgrade_Equilibrium: `+|VAL|% 能量 来自生命球, +|VAL|% 生命 来自能量球`,
|
||||
upgrade_MeleeCritDamage: `+|VAL|% 近战暴击伤害`,
|
||||
upgrade_PrimaryStatusChance: `+|VAL|% 主武器触发几率`,
|
||||
upgrade_SecondaryCritChance: `+|VAL|% 次要武器暴击几率`,
|
||||
upgrade_WarframeAbilityDuration: `+|VAL|% 技能持续时间`,
|
||||
upgrade_WarframeAbilityStrength: `+|VAL|% 技能强度`,
|
||||
upgrade_WarframeArmourMax: `+|VAL| 护甲`,
|
||||
upgrade_WarframeBlastProc: `[UNTRANSLATED] +|VAL| Shields on kill with Blast Damage`,
|
||||
upgrade_WarframeCastingSpeed: `+|VAL|% 施放速度`,
|
||||
upgrade_WarframeCorrosiveDamageBoost: `对受腐蚀状态影响的敌人 +|VAL|% 技能伤害`,
|
||||
upgrade_WarframeCorrosiveStack: `腐蚀状态最大堆叠数 +|VAL|`,
|
||||
upgrade_WarframeCritDamageBoost: `+|VAL|% 近战暴击伤害 (500能量以上翻倍)`,
|
||||
upgrade_WarframeElectricDamage: `+|VAL1|% 主武器伤害效果 (+|VAL2|% 每附加一个碎片)`,
|
||||
upgrade_WarframeElectricDamageBoost: `对受电能状态影响的敌人 +|VAL|% 技能伤害`,
|
||||
upgrade_WarframeEnergyMax: `+|VAL| 最大能量`,
|
||||
upgrade_WarframeGlobeEffectEnergy: `+|VAL|% 能量球效果`,
|
||||
upgrade_WarframeGlobeEffectHealth: `+|VAL|% 生命球效果`,
|
||||
upgrade_WarframeHealthMax: `+|VAL| 生命`,
|
||||
upgrade_WarframeHPBoostFromImpact: `每个被爆炸伤害击杀的敌人,补充 |VAL1|生命 (最大 |VAL2| 生命)`,
|
||||
upgrade_WarframeParkourVelocity: `+|VAL|% 跑酷速度`,
|
||||
upgrade_WarframeRadiationDamageBoost: `对受辐射状态影响的敌人 +|VAL|% 技能伤害`,
|
||||
upgrade_WarframeRegen: `+|VAL| 生命再生/s`,
|
||||
upgrade_WarframeShieldMax: `+|VAL| 护盾`,
|
||||
upgrade_WarframeStartingEnergy: `+|VAL|% 能量出生时`,
|
||||
upgrade_WarframeToxinDamage: `+|VAL|% 毒素伤害效果`,
|
||||
upgrade_WarframeToxinHeal: `+|VAL| 生命 对毒素状态的敌人造成伤害时`,
|
||||
upgrade_WeaponCritBoostFromHeat: `每个被火焰伤害杀死的敌人, 增加|VAL1|% 次要武器暴击几率 (最大 |VAL2|%)`,
|
||||
upgrade_AvatarAbilityRange: `+7.5% 技能范围`,
|
||||
upgrade_AvatarAbilityEfficiency: `+5% 技能效率`,
|
||||
upgrade_AvatarEnergyRegen: `+0.5 能量再生/秒`,
|
||||
upgrade_AvatarEnemyRadar: `+5米 敌方雷达`,
|
||||
upgrade_AvatarLootRadar: `+7米 战利品雷达`,
|
||||
upgrade_WeaponAmmoMax: `+15% 弹药最大容量`,
|
||||
upgrade_EnemyArmorReductionAura: `-3% 敌方护甲`,
|
||||
upgrade_OnExecutionAmmo: `怜悯之击 100% 补充主次要武器弹匣`,
|
||||
upgrade_OnExecutionHealthDrop: `怜悯之击 100% 几率 掉落生命球`,
|
||||
upgrade_OnExecutionEnergyDrop: `怜悯之击 50% 几率 掉落生命球`,
|
||||
upgrade_OnFailHackReset: `+50% 在入侵失败时重试`,
|
||||
upgrade_DamageReductionOnHack: `入侵时,+75% 伤害减免`,
|
||||
upgrade_OnExecutionReviveCompanion: `怜悯之击 减少同伴复苏时间 15秒`,
|
||||
upgrade_OnExecutionParkourSpeed: `怜悯之击 15秒内 +60% 跑酷速度`,
|
||||
upgrade_AvatarTimeLimitIncrease: `增加入侵限制时间`,
|
||||
upgrade_ElectrifyOnHack: `入侵时震慑20米之内的敌人`,
|
||||
upgrade_OnExecutionTerrify: `怜悯之击 50% 几率让 15米 以内的敌人恐慌`,
|
||||
upgrade_OnHackLockers: `入侵后解锁20米内的5个储物柜`,
|
||||
upgrade_OnExecutionBlind: `怜悯之击 致盲18米之内的敌人`,
|
||||
upgrade_OnExecutionDrainPower: `怜悯之击会使下一个技能有100%的机会获得+50%的技能强度`,
|
||||
upgrade_OnHackSprintSpeed: `入侵后+75%冲刺速度,持续15秒`,
|
||||
upgrade_SwiftExecute: `怜悯之击速度提升50%`,
|
||||
upgrade_OnHackInvis: `入侵后隐身15秒`,
|
||||
|
||||
prettier_sucks_ass: ``
|
||||
};
|
||||
|
Loading…
x
Reference in New Issue
Block a user