forked from OpenWF/SpaceNinjaServer
Compare commits
51 Commits
Author | SHA1 | Date | |
---|---|---|---|
2e9d3c33b6 | |||
7c8e8fe049 | |||
0c4065619d | |||
dabca46e88 | |||
7819d87bbe | |||
b8b8b6a6c6 | |||
9af0e06b70 | |||
f8d0c9e0cb | |||
16e80acb53 | |||
6691d4e402 | |||
3dcd2663d3 | |||
ffeffe2796 | |||
a9f1368cb7 | |||
cccf6f04a5 | |||
1ead581780 | |||
145d21e30e | |||
6c2055a246 | |||
01e490768c | |||
2e8fe799d7 | |||
53976378bb | |||
4e832d3b2c | |||
8c1147998d | |||
3e99e069be | |||
9731004de6 | |||
b98a88b700 | |||
6023f1c113 | |||
c6dd8bfb81 | |||
3053112428 | |||
f448d03880 | |||
d00fbed46f | |||
c283d61399 | |||
12d09531b3 | |||
b67ddf6df2 | |||
8b27fcf459 | |||
071ef528ea | |||
71d1b6094c | |||
fcc11206cc | |||
3c019e41b9 | |||
54a73ad5d7 | |||
62eeb313ec | |||
62d4b9f6cb | |||
1d813a1b1b | |||
4823406229 | |||
bdc41de8bb | |||
60236a1154 | |||
1979b20f8c | |||
c736310ff3 | |||
2b555a6456 | |||
870c964854 | |||
4535b193e0 | |||
943574bf3a |
3
.github/workflows/build.yml
vendored
3
.github/workflows/build.yml
vendored
@ -1,6 +1,7 @@
|
|||||||
name: Build
|
name: Build
|
||||||
on:
|
on:
|
||||||
push: {}
|
push:
|
||||||
|
branches: ["main"]
|
||||||
pull_request: {}
|
pull_request: {}
|
||||||
jobs:
|
jobs:
|
||||||
build:
|
build:
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM node:18-alpine3.19
|
FROM node:24-alpine3.21
|
||||||
|
|
||||||
ENV APP_MONGODB_URL=mongodb://mongodb:27017/openWF
|
ENV APP_MONGODB_URL=mongodb://mongodb:27017/openWF
|
||||||
ENV APP_MY_ADDRESS=localhost
|
ENV APP_MY_ADDRESS=localhost
|
||||||
|
@ -14,7 +14,8 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi
|
|||||||
|
|
||||||
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
|
- `logger.level` can be `fatal`, `error`, `warn`, `info`, `http`, `debug`, or `trace`.
|
||||||
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
|
- `myIrcAddresses` can be used to point to an IRC server. If not provided, defaults to `[ myAddress ]`.
|
||||||
- `worldState.lockTime` will lock the time provided in worldState if nonzero, e.g. `1743202800` for night in POE.
|
- `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.nightwaveOverride` will lock the nightwave season, assuming the client is new enough for it. Valid values:
|
- `worldState.nightwaveOverride` will lock the nightwave season, assuming the client is new enough for it. Valid values:
|
||||||
- `RadioLegionIntermission13Syndicate` for Nora's Mix Vol. 9
|
- `RadioLegionIntermission13Syndicate` for Nora's Mix Vol. 9
|
||||||
- `RadioLegionIntermission12Syndicate` for Nora's Mix Vol. 8
|
- `RadioLegionIntermission12Syndicate` for Nora's Mix Vol. 8
|
||||||
@ -32,3 +33,4 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi
|
|||||||
- `RadioLegion2Syndicate` for The Emissary
|
- `RadioLegion2Syndicate` for The Emissary
|
||||||
- `RadioLegionIntermissionSyndicate` for Intermission I
|
- `RadioLegionIntermissionSyndicate` for Intermission I
|
||||||
- `RadioLegionSyndicate` for The Wolf of Saturn Six
|
- `RadioLegionSyndicate` for The Wolf of Saturn Six
|
||||||
|
- `worldState.circuitGameModes` can be provided with an array of valid game modes (`Survival`, `VoidFlood`, `Excavation`, `Defense`, `Exterminate`, `Assassination`, `Alchemy`)
|
||||||
|
@ -50,12 +50,18 @@
|
|||||||
"noDojoResearchTime": false,
|
"noDojoResearchTime": false,
|
||||||
"fastClanAscension": false,
|
"fastClanAscension": false,
|
||||||
"spoofMasteryRank": -1,
|
"spoofMasteryRank": -1,
|
||||||
|
"nightwaveStandingMultiplier": 1,
|
||||||
"worldState": {
|
"worldState": {
|
||||||
"creditBoost": false,
|
"creditBoost": false,
|
||||||
"affinityBoost": false,
|
"affinityBoost": false,
|
||||||
"resourceBoost": false,
|
"resourceBoost": false,
|
||||||
"starDays": true,
|
"starDays": true,
|
||||||
"lockTime": 0,
|
"eidolonOverride": "",
|
||||||
"nightwaveOverride": ""
|
"vallisOverride": "",
|
||||||
|
"nightwaveOverride": "",
|
||||||
|
"circuitGameModes": null
|
||||||
|
},
|
||||||
|
"dev": {
|
||||||
|
"keepVendorsExpired": false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
8
package-lock.json
generated
8
package-lock.json
generated
@ -18,7 +18,7 @@
|
|||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": "^5.5",
|
||||||
"warframe-public-export-plus": "^0.5.65",
|
"warframe-public-export-plus": "^0.5.68",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
@ -3814,9 +3814,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/warframe-public-export-plus": {
|
"node_modules/warframe-public-export-plus": {
|
||||||
"version": "0.5.65",
|
"version": "0.5.68",
|
||||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.65.tgz",
|
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.68.tgz",
|
||||||
"integrity": "sha512-y/HN61lE5g8gx0Giutdl/jzQnQmw1u2uI0BiwKVW341nf42sKWQPsKsCVTL5x9MIDYyRCbFsMU+PazKC7byMdg=="
|
"integrity": "sha512-KMmwCVeQ4k+EN73UZqxnM+qQdPsST8geWoJCP7US5LT6JcRxa8ptmqYXwCzaLtckBLZyVbamsxKZAxPPJckxsA=="
|
||||||
},
|
},
|
||||||
"node_modules/warframe-riven-info": {
|
"node_modules/warframe-riven-info": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": "^5.5",
|
||||||
"warframe-public-export-plus": "^0.5.65",
|
"warframe-public-export-plus": "^0.5.68",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
|
@ -118,7 +118,7 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
pet.Details!.Status = canSetActive ? Status.StatusAvailable : Status.StatusIncubating;
|
pet.Details!.Status = canSetActive ? Status.StatusAvailable : Status.StatusStasis;
|
||||||
} else if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
} else if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
||||||
InventoryChanges = {
|
InventoryChanges = {
|
||||||
...InventoryChanges,
|
...InventoryChanges,
|
||||||
|
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];
|
@ -30,15 +30,14 @@ export const fishmongerController: RequestHandler = async (req, res) => {
|
|||||||
miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 });
|
miscItemChanges.push({ ItemType: fish.ItemType, ItemCount: fish.ItemCount * -1 });
|
||||||
}
|
}
|
||||||
addMiscItems(inventory, miscItemChanges);
|
addMiscItems(inventory, miscItemChanges);
|
||||||
let affiliationMod;
|
if (gainedStanding && syndicateTag) addStanding(inventory, syndicateTag, gainedStanding);
|
||||||
if (gainedStanding && syndicateTag) affiliationMod = addStanding(inventory, syndicateTag, gainedStanding);
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: {
|
InventoryChanges: {
|
||||||
MiscItems: miscItemChanges
|
MiscItems: miscItemChanges
|
||||||
},
|
},
|
||||||
SyndicateTag: syndicateTag,
|
SyndicateTag: syndicateTag,
|
||||||
StandingChange: affiliationMod?.Standing || 0
|
StandingChange: gainedStanding
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -43,7 +43,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
inventory.FocusAbility ??= focusType;
|
inventory.FocusAbility ??= focusType;
|
||||||
inventory.FocusUpgrades.push({ ItemType: focusType });
|
inventory.FocusUpgrades.push({ ItemType: focusType });
|
||||||
if (inventory.FocusXP) {
|
if (inventory.FocusXP) {
|
||||||
inventory.FocusXP[focusPolarity] -= cost;
|
inventory.FocusXP[focusPolarity]! -= cost;
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
@ -78,7 +78,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
|
cost += ExportFocusUpgrades[focusType].baseFocusPointCost;
|
||||||
inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
|
inventory.FocusUpgrades.push({ ItemType: focusType, Level: 0 });
|
||||||
}
|
}
|
||||||
inventory.FocusXP![focusPolarity] -= cost;
|
inventory.FocusXP![focusPolarity]! -= cost;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
FocusTypes: request.FocusTypes,
|
FocusTypes: request.FocusTypes,
|
||||||
@ -96,7 +96,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
|
const focusUpgradeDb = inventory.FocusUpgrades.find(entry => entry.ItemType == focusUpgrade.ItemType)!;
|
||||||
focusUpgradeDb.Level = focusUpgrade.Level;
|
focusUpgradeDb.Level = focusUpgrade.Level;
|
||||||
}
|
}
|
||||||
inventory.FocusXP![focusPolarity] -= cost;
|
inventory.FocusXP![focusPolarity]! -= cost;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
FocusInfos: request.FocusInfos,
|
FocusInfos: request.FocusInfos,
|
||||||
@ -123,7 +123,7 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
|
const request = JSON.parse(String(req.body)) as IUnbindUpgradeRequest;
|
||||||
const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
|
const focusPolarity = focusTypeToPolarity(request.FocusTypes[0]);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
inventory.FocusXP![focusPolarity] -= 750_000 * request.FocusTypes.length;
|
inventory.FocusXP![focusPolarity]! -= 750_000 * request.FocusTypes.length;
|
||||||
addMiscItems(inventory, [
|
addMiscItems(inventory, [
|
||||||
{
|
{
|
||||||
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem",
|
ItemType: "/Lotus/Types/Gameplay/Eidolon/Resources/SentientShards/SentientShardBrilliantItem",
|
||||||
@ -168,8 +168,10 @@ export const focusController: RequestHandler = async (req, res) => {
|
|||||||
shard.ItemCount *= -1;
|
shard.ItemCount *= -1;
|
||||||
}
|
}
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
inventory.FocusXP ??= { AP_POWER: 0, AP_TACTIC: 0, AP_DEFENSE: 0, AP_ATTACK: 0, AP_WARD: 0 };
|
const polarity = request.Polarity;
|
||||||
inventory.FocusXP[request.Polarity] += xp;
|
inventory.FocusXP ??= {};
|
||||||
|
inventory.FocusXP[polarity] ??= 0;
|
||||||
|
inventory.FocusXP[polarity] += xp;
|
||||||
addMiscItems(inventory, request.Shards);
|
addMiscItems(inventory, request.Shards);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
break;
|
break;
|
||||||
|
@ -2,6 +2,7 @@ import { RequestHandler } from "express";
|
|||||||
import { applyStandingToVendorManifest, getVendorManifestByTypeName } from "@/src/services/serversideVendorsService";
|
import { applyStandingToVendorManifest, getVendorManifestByTypeName } from "@/src/services/serversideVendorsService";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { config } from "@/src/services/configService";
|
||||||
|
|
||||||
export const getVendorInfoController: RequestHandler = async (req, res) => {
|
export const getVendorInfoController: RequestHandler = async (req, res) => {
|
||||||
let manifest = getVendorManifestByTypeName(req.query.vendor as string);
|
let manifest = getVendorManifestByTypeName(req.query.vendor as string);
|
||||||
@ -14,6 +15,14 @@ export const getVendorInfoController: RequestHandler = async (req, res) => {
|
|||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
manifest = applyStandingToVendorManifest(inventory, manifest);
|
manifest = applyStandingToVendorManifest(inventory, manifest);
|
||||||
|
if (config.dev?.keepVendorsExpired) {
|
||||||
|
manifest = {
|
||||||
|
VendorInfo: {
|
||||||
|
...manifest.VendorInfo,
|
||||||
|
Expiry: { $date: { $numberLong: "0" } }
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
res.json(manifest);
|
res.json(manifest);
|
||||||
|
@ -11,7 +11,7 @@ import {
|
|||||||
scaleRequiredCount,
|
scaleRequiredCount,
|
||||||
setGuildTechLogState
|
setGuildTechLogState
|
||||||
} from "@/src/services/guildService";
|
} from "@/src/services/guildService";
|
||||||
import { ExportDojoRecipes } from "warframe-public-export-plus";
|
import { ExportDojoRecipes, ExportRailjackWeapons } from "warframe-public-export-plus";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import {
|
import {
|
||||||
addCrewShipWeaponSkin,
|
addCrewShipWeaponSkin,
|
||||||
@ -442,6 +442,7 @@ const finishComponentRepair = (
|
|||||||
...(category == "CrewShipWeaponSkins"
|
...(category == "CrewShipWeaponSkins"
|
||||||
? addCrewShipWeaponSkin(inventory, salvageItem.ItemType, salvageItem.UpgradeFingerprint)
|
? addCrewShipWeaponSkin(inventory, salvageItem.ItemType, salvageItem.UpgradeFingerprint)
|
||||||
: addEquipment(inventory, category, salvageItem.ItemType, {
|
: addEquipment(inventory, category, salvageItem.ItemType, {
|
||||||
|
UpgradeType: ExportRailjackWeapons[salvageItem.ItemType].defaultUpgrades?.[0].ItemType,
|
||||||
UpgradeFingerprint: salvageItem.UpgradeFingerprint
|
UpgradeFingerprint: salvageItem.UpgradeFingerprint
|
||||||
})),
|
})),
|
||||||
...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, false)
|
...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, false)
|
||||||
|
@ -30,8 +30,9 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
|
|||||||
const request = getJSONfromString<IShardInstallRequest>(String(req.body));
|
const request = getJSONfromString<IShardInstallRequest>(String(req.body));
|
||||||
const inventory = await getInventory(account._id.toString());
|
const inventory = await getInventory(account._id.toString());
|
||||||
const suit = inventory.Suits.id(request.SuitId.$oid)!;
|
const suit = inventory.Suits.id(request.SuitId.$oid)!;
|
||||||
if (!suit.ArchonCrystalUpgrades || suit.ArchonCrystalUpgrades.length != 5) {
|
suit.ArchonCrystalUpgrades ??= [];
|
||||||
suit.ArchonCrystalUpgrades = [{}, {}, {}, {}, {}];
|
while (suit.ArchonCrystalUpgrades.length < request.Slot) {
|
||||||
|
suit.ArchonCrystalUpgrades.push({});
|
||||||
}
|
}
|
||||||
suit.ArchonCrystalUpgrades[request.Slot] = {
|
suit.ArchonCrystalUpgrades[request.Slot] = {
|
||||||
UpgradeType: request.UpgradeType,
|
UpgradeType: request.UpgradeType,
|
||||||
@ -92,7 +93,8 @@ export const infestedFoundryController: RequestHandler = async (req, res) => {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// remove from suit
|
// remove from suit
|
||||||
suit.ArchonCrystalUpgrades![request.Slot] = {};
|
suit.ArchonCrystalUpgrades![request.Slot].UpgradeType = undefined;
|
||||||
|
suit.ArchonCrystalUpgrades![request.Slot].Color = undefined;
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
import { version_compare } from "@/src/helpers/inventoryHelpers";
|
import { version_compare } from "@/src/helpers/inventoryHelpers";
|
||||||
import {
|
import {
|
||||||
|
antivirusMods,
|
||||||
consumeModCharge,
|
consumeModCharge,
|
||||||
decodeNemesisGuess,
|
decodeNemesisGuess,
|
||||||
encodeNemesisGuess,
|
encodeNemesisGuess,
|
||||||
@ -16,6 +17,7 @@ import {
|
|||||||
IKnifeResponse
|
IKnifeResponse
|
||||||
} from "@/src/helpers/nemesisHelpers";
|
} from "@/src/helpers/nemesisHelpers";
|
||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
||||||
import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
import { freeUpSlot, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountForRequest } from "@/src/services/loginService";
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
@ -134,34 +136,37 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
for (const upgrade of body.knife!.AttachedUpgrades) {
|
for (const upgrade of body.knife!.AttachedUpgrades) {
|
||||||
switch (upgrade.ItemType) {
|
switch (upgrade.ItemType) {
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
|
||||||
antivirusGain += 10;
|
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
|
||||||
break;
|
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod":
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndWeaponDamageOnUseMod":
|
||||||
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
|
||||||
antivirusGain += 10;
|
antivirusGain += 10;
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
break;
|
break;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusLargeOnSingleUseMod": // Instant Secure
|
||||||
antivirusGain += 15;
|
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
|
||||||
break;
|
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield
|
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusOnUseMod": // Immuno Shield
|
||||||
antivirusGain += 15;
|
antivirusGain += 15;
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
break;
|
break;
|
||||||
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusSmallOnSingleUseMod":
|
|
||||||
antivirusGain += 10;
|
|
||||||
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
|
||||||
break;
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
inventory.Nemesis!.HenchmenKilled += antivirusGain;
|
inventory.Nemesis!.HenchmenKilled += antivirusGain;
|
||||||
}
|
|
||||||
|
|
||||||
if (inventory.Nemesis!.HenchmenKilled >= 100) {
|
if (inventory.Nemesis!.HenchmenKilled >= 100) {
|
||||||
inventory.Nemesis!.HenchmenKilled = 100;
|
inventory.Nemesis!.HenchmenKilled = 100;
|
||||||
|
// Client doesn't seem to request mode=w for infested liches, so weakening it here.
|
||||||
|
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!.InfNodes = getInfNodes(getNemesisManifest(inventory.Nemesis!.manifest), 0);
|
inventory.Nemesis!.InfNodes = getInfNodes(getNemesisManifest(inventory.Nemesis!.manifest), 0);
|
||||||
|
}
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json(response);
|
res.json(response);
|
||||||
@ -198,16 +203,28 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
guess[body.position].result = correct ? GUESS_CORRECT : GUESS_INCORRECT;
|
guess[body.position].result = correct ? GUESS_CORRECT : GUESS_INCORRECT;
|
||||||
inventory.Nemesis!.GuessHistory[inventory.Nemesis!.GuessHistory.length - 1] = encodeNemesisGuess(guess);
|
inventory.Nemesis!.GuessHistory[inventory.Nemesis!.GuessHistory.length - 1] = encodeNemesisGuess(guess);
|
||||||
|
|
||||||
// Increase rank if incorrect
|
const response: INemesisRequiemResponse = {};
|
||||||
let RankIncrease: number | undefined;
|
if (correct) {
|
||||||
if (!correct) {
|
if (body.position == 2) {
|
||||||
RankIncrease = 1;
|
// That was all 3 guesses correct, nemesis is now weakened.
|
||||||
|
inventory.Nemesis!.InfNodes = [
|
||||||
|
{
|
||||||
|
Node: getNemesisManifest(inventory.Nemesis!.manifest).showdownNode,
|
||||||
|
Influence: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
inventory.Nemesis!.Weakened = true;
|
||||||
|
await consumePasscodeModCharges(inventory, response);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Guess was incorrect, increase rank
|
||||||
|
response.RankIncrease = 1;
|
||||||
const manifest = getNemesisManifest(inventory.Nemesis!.manifest);
|
const manifest = getNemesisManifest(inventory.Nemesis!.manifest);
|
||||||
inventory.Nemesis!.Rank = Math.min(inventory.Nemesis!.Rank + 1, manifest.systemIndexes.length - 1);
|
inventory.Nemesis!.Rank = Math.min(inventory.Nemesis!.Rank + 1, manifest.systemIndexes.length - 1);
|
||||||
inventory.Nemesis!.InfNodes = getInfNodes(manifest, inventory.Nemesis!.Rank);
|
inventory.Nemesis!.InfNodes = getInfNodes(manifest, inventory.Nemesis!.Rank);
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({ RankIncrease });
|
res.json(response);
|
||||||
}
|
}
|
||||||
} else if ((req.query.mode as string) == "rs") {
|
} else if ((req.query.mode as string) == "rs") {
|
||||||
// report spawn; POST but no application data in body
|
// report spawn; POST but no application data in body
|
||||||
@ -283,6 +300,10 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
);
|
);
|
||||||
//const body = getJSONfromString<INemesisWeakenRequest>(String(req.body));
|
//const body = getJSONfromString<INemesisWeakenRequest>(String(req.body));
|
||||||
|
|
||||||
|
if (inventory.Nemesis!.Weakened) {
|
||||||
|
logger.warn(`client is weakening an already-weakened nemesis?!`);
|
||||||
|
}
|
||||||
|
|
||||||
inventory.Nemesis!.InfNodes = [
|
inventory.Nemesis!.InfNodes = [
|
||||||
{
|
{
|
||||||
Node: getNemesisManifest(inventory.Nemesis!.manifest).showdownNode,
|
Node: getNemesisManifest(inventory.Nemesis!.manifest).showdownNode,
|
||||||
@ -291,20 +312,11 @@ export const nemesisController: RequestHandler = async (req, res) => {
|
|||||||
];
|
];
|
||||||
inventory.Nemesis!.Weakened = true;
|
inventory.Nemesis!.Weakened = true;
|
||||||
|
|
||||||
const response: IKnifeResponse & { target: INemesisClient } = {
|
const response: INemesisWeakenResponse = {
|
||||||
target: inventory.toJSON<IInventoryClient>().Nemesis!
|
target: inventory.toJSON<IInventoryClient>().Nemesis!
|
||||||
};
|
};
|
||||||
|
|
||||||
// Consume charge of the correct requiem mod(s)
|
await consumePasscodeModCharges(inventory, response);
|
||||||
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();
|
await inventory.save();
|
||||||
res.json(response);
|
res.json(response);
|
||||||
@ -362,11 +374,19 @@ interface INemesisRequiemRequest {
|
|||||||
knife?: IKnife;
|
knife?: IKnife;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
interface INemesisRequiemResponse extends IKnifeResponse {
|
||||||
|
RankIncrease?: number;
|
||||||
|
}
|
||||||
|
|
||||||
// interface INemesisWeakenRequest {
|
// interface INemesisWeakenRequest {
|
||||||
// target: INemesisClient;
|
// target: INemesisClient;
|
||||||
// knife: IKnife;
|
// knife: IKnife;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
|
interface INemesisWeakenResponse extends IKnifeResponse {
|
||||||
|
target: INemesisClient;
|
||||||
|
}
|
||||||
|
|
||||||
interface IKnife {
|
interface IKnife {
|
||||||
Item: IEquipmentClient;
|
Item: IEquipmentClient;
|
||||||
Skins: IWeaponSkinClient[];
|
Skins: IWeaponSkinClient[];
|
||||||
@ -375,3 +395,18 @@ interface IKnife {
|
|||||||
AttachedUpgrades: IUpgradeClient[];
|
AttachedUpgrades: IUpgradeClient[];
|
||||||
HiddenWhenHolstered: boolean;
|
HiddenWhenHolstered: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const consumePasscodeModCharges = async (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
response: IKnifeResponse
|
||||||
|
): Promise<void> => {
|
||||||
|
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
|
||||||
|
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
|
||||||
|
const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
|
||||||
|
const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
|
||||||
|
const modTypes = getNemesisPasscodeModTypes(inventory.Nemesis!);
|
||||||
|
for (const modType of modTypes) {
|
||||||
|
const upgrade = getKnifeUpgrade(inventory, dataknifeUpgrades, modType);
|
||||||
|
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
@ -24,7 +24,7 @@ export const saveDialogueController: RequestHandler = async (req, res) => {
|
|||||||
inventory.DialogueHistory.Dialogues ??= [];
|
inventory.DialogueHistory.Dialogues ??= [];
|
||||||
const dialogue = getDialogue(inventory, request.DialogueName);
|
const dialogue = getDialogue(inventory, request.DialogueName);
|
||||||
dialogue.Rank = request.Rank;
|
dialogue.Rank = request.Rank;
|
||||||
dialogue.Chemistry = request.Chemistry;
|
dialogue.Chemistry += request.Chemistry;
|
||||||
dialogue.QueuedDialogues = request.QueuedDialogues;
|
dialogue.QueuedDialogues = request.QueuedDialogues;
|
||||||
for (const bool of request.Booleans) {
|
for (const bool of request.Booleans) {
|
||||||
dialogue.Booleans.push(bool);
|
dialogue.Booleans.push(bool);
|
||||||
|
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[];
|
||||||
|
}
|
@ -3,7 +3,7 @@ import { RequestHandler } from "express";
|
|||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { ExportSyndicates, ISyndicateSacrifice } from "warframe-public-export-plus";
|
import { ExportSyndicates, ISyndicateSacrifice } from "warframe-public-export-plus";
|
||||||
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
|
||||||
import { addMiscItems, combineInventoryChanges, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
import { addMiscItem, combineInventoryChanges, getInventory, updateCurrency } from "@/src/services/inventoryService";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { toStoreItem } from "@/src/services/itemDataService";
|
import { toStoreItem } from "@/src/services/itemDataService";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
@ -18,50 +18,51 @@ export const syndicateSacrificeController: RequestHandler = async (request, resp
|
|||||||
syndicate = inventory.Affiliations[inventory.Affiliations.push({ Tag: data.AffiliationTag, Standing: 0 }) - 1];
|
syndicate = inventory.Affiliations[inventory.Affiliations.push({ Tag: data.AffiliationTag, Standing: 0 }) - 1];
|
||||||
}
|
}
|
||||||
|
|
||||||
const level = data.SacrificeLevel - (syndicate.Title ?? 0);
|
const oldLevel = syndicate.Title ?? 0;
|
||||||
|
const levelIncrease = data.SacrificeLevel - oldLevel;
|
||||||
|
if (levelIncrease < 0) {
|
||||||
|
throw new Error(`syndicate sacrifice can not decrease level`);
|
||||||
|
}
|
||||||
|
if (levelIncrease > 1 && !data.AllowMultiple) {
|
||||||
|
throw new Error(`desired syndicate level is an increase of ${levelIncrease}, max. allowed increase is 1`);
|
||||||
|
}
|
||||||
|
|
||||||
const res: ISyndicateSacrificeResponse = {
|
const res: ISyndicateSacrificeResponse = {
|
||||||
AffiliationTag: data.AffiliationTag,
|
AffiliationTag: data.AffiliationTag,
|
||||||
InventoryChanges: {},
|
InventoryChanges: {},
|
||||||
Level: data.SacrificeLevel,
|
Level: data.SacrificeLevel,
|
||||||
LevelIncrease: level <= 0 ? 1 : level,
|
LevelIncrease: data.SacrificeLevel < 0 ? 1 : levelIncrease,
|
||||||
NewEpisodeReward: false
|
NewEpisodeReward: false
|
||||||
};
|
};
|
||||||
|
|
||||||
|
// Process sacrifices and rewards for every level we're reaching
|
||||||
const manifest = ExportSyndicates[data.AffiliationTag];
|
const manifest = ExportSyndicates[data.AffiliationTag];
|
||||||
|
for (let level = oldLevel + Math.min(levelIncrease, 1); level <= data.SacrificeLevel; ++level) {
|
||||||
let sacrifice: ISyndicateSacrifice | undefined;
|
let sacrifice: ISyndicateSacrifice | undefined;
|
||||||
let reward: string | undefined;
|
if (level == 0) {
|
||||||
if (data.SacrificeLevel == 0) {
|
|
||||||
sacrifice = manifest.initiationSacrifice;
|
sacrifice = manifest.initiationSacrifice;
|
||||||
reward = manifest.initiationReward;
|
if (manifest.initiationReward) {
|
||||||
|
combineInventoryChanges(
|
||||||
|
res.InventoryChanges,
|
||||||
|
(await handleStoreItemAcquisition(manifest.initiationReward, inventory)).InventoryChanges
|
||||||
|
);
|
||||||
|
}
|
||||||
syndicate.Initiated = true;
|
syndicate.Initiated = true;
|
||||||
} else {
|
} else {
|
||||||
sacrifice = manifest.titles?.find(x => x.level == data.SacrificeLevel)?.sacrifice;
|
sacrifice = manifest.titles?.find(x => x.level == level)?.sacrifice;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (sacrifice) {
|
if (sacrifice) {
|
||||||
res.InventoryChanges = { ...updateCurrency(inventory, sacrifice.credits, false) };
|
updateCurrency(inventory, sacrifice.credits, false, res.InventoryChanges);
|
||||||
|
|
||||||
const miscItemChanges = sacrifice.items.map(x => ({
|
for (const item of sacrifice.items) {
|
||||||
ItemType: x.ItemType,
|
addMiscItem(inventory, item.ItemType, item.ItemCount * -1, res.InventoryChanges);
|
||||||
ItemCount: x.ItemCount * -1
|
|
||||||
}));
|
|
||||||
addMiscItems(inventory, miscItemChanges);
|
|
||||||
res.InventoryChanges.MiscItems = miscItemChanges;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
syndicate.Title ??= 0;
|
|
||||||
syndicate.Title += 1;
|
|
||||||
|
|
||||||
if (reward) {
|
|
||||||
combineInventoryChanges(
|
|
||||||
res.InventoryChanges,
|
|
||||||
(await handleStoreItemAcquisition(reward, inventory)).InventoryChanges
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Quacks like a nightwave syndicate?
|
// Quacks like a nightwave syndicate?
|
||||||
if (manifest.dailyChallenges) {
|
if (manifest.dailyChallenges) {
|
||||||
const title = manifest.titles!.find(x => x.level == syndicate.Title);
|
const title = manifest.titles!.find(x => x.level == level);
|
||||||
if (title) {
|
if (title) {
|
||||||
res.NewEpisodeReward = true;
|
res.NewEpisodeReward = true;
|
||||||
let rewardType: string;
|
let rewardType: string;
|
||||||
@ -78,20 +79,22 @@ export const syndicateSacrificeController: RequestHandler = async (request, resp
|
|||||||
if (Object.keys(rewardInventoryChanges).length == 0) {
|
if (Object.keys(rewardInventoryChanges).length == 0) {
|
||||||
logger.debug(`nightwave rank up reward did not seem to get added, giving 50 creds instead`);
|
logger.debug(`nightwave rank up reward did not seem to get added, giving 50 creds instead`);
|
||||||
const nightwaveCredsItemType = manifest.titles![0].reward!.ItemType;
|
const nightwaveCredsItemType = manifest.titles![0].reward!.ItemType;
|
||||||
rewardInventoryChanges.MiscItems = [{ ItemType: nightwaveCredsItemType, ItemCount: 50 }];
|
addMiscItem(inventory, nightwaveCredsItemType, 50, rewardInventoryChanges);
|
||||||
addMiscItems(inventory, rewardInventoryChanges.MiscItems);
|
|
||||||
}
|
}
|
||||||
combineInventoryChanges(res.InventoryChanges, rewardInventoryChanges);
|
combineInventoryChanges(res.InventoryChanges, rewardInventoryChanges);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
if (syndicate.Title > 0 && manifest.favours.find(x => x.rankUpReward && x.requiredLevel == syndicate.Title)) {
|
if (level > 0 && manifest.favours.find(x => x.rankUpReward && x.requiredLevel == level)) {
|
||||||
syndicate.FreeFavorsEarned ??= [];
|
syndicate.FreeFavorsEarned ??= [];
|
||||||
if (!syndicate.FreeFavorsEarned.includes(syndicate.Title)) {
|
if (!syndicate.FreeFavorsEarned.includes(level)) {
|
||||||
syndicate.FreeFavorsEarned.push(syndicate.Title);
|
syndicate.FreeFavorsEarned.push(level);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Commit
|
||||||
|
syndicate.Title = data.SacrificeLevel < 0 ? data.SacrificeLevel + 1 : data.SacrificeLevel;
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
response.json(res);
|
response.json(res);
|
||||||
|
@ -5,7 +5,7 @@ import { IMiscItem, InventorySlot } from "@/src/types/inventoryTypes/inventoryTy
|
|||||||
import { IOid } from "@/src/types/commonTypes";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import { ExportSyndicates, ExportWeapons } from "warframe-public-export-plus";
|
import { ExportSyndicates, ExportWeapons } from "warframe-public-export-plus";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IAffiliationMods, IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { EquipmentFeatures } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
|
|
||||||
export const syndicateStandingBonusController: RequestHandler = async (req, res) => {
|
export const syndicateStandingBonusController: RequestHandler = async (req, res) => {
|
||||||
@ -54,13 +54,14 @@ export const syndicateStandingBonusController: RequestHandler = async (req, res)
|
|||||||
inventoryChanges[slotBin] = { count: -1, platinum: 0, Slots: 1 };
|
inventoryChanges[slotBin] = { count: -1, platinum: 0, Slots: 1 };
|
||||||
}
|
}
|
||||||
|
|
||||||
const affiliationMod = addStanding(inventory, request.Operation.AffiliationTag, gainedStanding, true);
|
const affiliationMods: IAffiliationMods[] = [];
|
||||||
|
addStanding(inventory, request.Operation.AffiliationTag, gainedStanding, affiliationMods, true);
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({
|
res.json({
|
||||||
InventoryChanges: inventoryChanges,
|
InventoryChanges: inventoryChanges,
|
||||||
AffiliationMods: [affiliationMod]
|
AffiliationMods: affiliationMods
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -35,6 +35,17 @@ const trainingResultController: RequestHandler = async (req, res): Promise<void>
|
|||||||
inventory.PlayerLevel += 1;
|
inventory.PlayerLevel += 1;
|
||||||
inventory.TradesRemaining += 1;
|
inventory.TradesRemaining += 1;
|
||||||
|
|
||||||
|
if (inventory.PlayerLevel == 2) {
|
||||||
|
await createMessage(accountId, [
|
||||||
|
{
|
||||||
|
sndr: "/Lotus/Language/Game/Maroo",
|
||||||
|
msg: "/Lotus/Language/Clan/MarooClanSearchDesc",
|
||||||
|
sub: "/Lotus/Language/Clan/MarooClanSearchTitle",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Maroo.png"
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
await createMessage(accountId, [
|
await createMessage(accountId, [
|
||||||
{
|
{
|
||||||
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
|
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
|
||||||
|
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[];
|
||||||
|
}
|
@ -11,8 +11,11 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
|||||||
|
|
||||||
const inventory = await getInventory(
|
const inventory = await getInventory(
|
||||||
account._id.toString(),
|
account._id.toString(),
|
||||||
"ChallengeProgress SeasonChallengeHistory Affiliations"
|
"ChallengesFixVersion ChallengeProgress SeasonChallengeHistory Affiliations"
|
||||||
);
|
);
|
||||||
|
if (challenges.ChallengesFixVersion !== undefined) {
|
||||||
|
inventory.ChallengesFixVersion = challenges.ChallengesFixVersion;
|
||||||
|
}
|
||||||
let affiliationMods: IAffiliationMods[] = [];
|
let affiliationMods: IAffiliationMods[] = [];
|
||||||
if (challenges.ChallengeProgress) {
|
if (challenges.ChallengeProgress) {
|
||||||
affiliationMods = addChallenges(
|
affiliationMods = addChallenges(
|
||||||
@ -40,6 +43,7 @@ export const updateChallengeProgressController: RequestHandler = async (req, res
|
|||||||
};
|
};
|
||||||
|
|
||||||
interface IUpdateChallengeProgressRequest {
|
interface IUpdateChallengeProgressRequest {
|
||||||
|
ChallengesFixVersion?: number;
|
||||||
ChallengeProgress?: IChallengeProgress[];
|
ChallengeProgress?: IChallengeProgress[];
|
||||||
SeasonChallengeHistory?: ISeasonChallenge[];
|
SeasonChallengeHistory?: ISeasonChallenge[];
|
||||||
SeasonChallengeCompletions?: ISeasonChallenge[];
|
SeasonChallengeCompletions?: ISeasonChallenge[];
|
||||||
|
@ -3,6 +3,7 @@ import { getDict, getItemName, getString } from "@/src/services/itemDataService"
|
|||||||
import {
|
import {
|
||||||
ExportArcanes,
|
ExportArcanes,
|
||||||
ExportAvionics,
|
ExportAvionics,
|
||||||
|
ExportBoosters,
|
||||||
ExportCustoms,
|
ExportCustoms,
|
||||||
ExportDrones,
|
ExportDrones,
|
||||||
ExportGear,
|
ExportGear,
|
||||||
@ -19,7 +20,6 @@ import {
|
|||||||
ExportWeapons,
|
ExportWeapons,
|
||||||
TRelicQuality
|
TRelicQuality
|
||||||
} from "warframe-public-export-plus";
|
} from "warframe-public-export-plus";
|
||||||
import archonCrystalUpgrades from "@/static/fixed_responses/webuiArchonCrystalUpgrades.json";
|
|
||||||
import allIncarnons from "@/static/fixed_responses/allIncarnonList.json";
|
import allIncarnons from "@/static/fixed_responses/allIncarnonList.json";
|
||||||
|
|
||||||
interface ListedItem {
|
interface ListedItem {
|
||||||
@ -35,7 +35,6 @@ interface ListedItem {
|
|||||||
}
|
}
|
||||||
|
|
||||||
interface ItemLists {
|
interface ItemLists {
|
||||||
archonCrystalUpgrades: Record<string, string>;
|
|
||||||
uniqueLevelCaps: Record<string, number>;
|
uniqueLevelCaps: Record<string, number>;
|
||||||
Suits: ListedItem[];
|
Suits: ListedItem[];
|
||||||
LongGuns: ListedItem[];
|
LongGuns: ListedItem[];
|
||||||
@ -55,6 +54,7 @@ interface ItemLists {
|
|||||||
KubrowPets: ListedItem[];
|
KubrowPets: ListedItem[];
|
||||||
EvolutionProgress: ListedItem[];
|
EvolutionProgress: ListedItem[];
|
||||||
mods: ListedItem[];
|
mods: ListedItem[];
|
||||||
|
Boosters: ListedItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
||||||
@ -67,7 +67,6 @@ const relicQualitySuffixes: Record<TRelicQuality, string> = {
|
|||||||
const getItemListsController: RequestHandler = (req, response) => {
|
const getItemListsController: RequestHandler = (req, response) => {
|
||||||
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
|
const lang = getDict(typeof req.query.lang == "string" ? req.query.lang : "en");
|
||||||
const res: ItemLists = {
|
const res: ItemLists = {
|
||||||
archonCrystalUpgrades,
|
|
||||||
uniqueLevelCaps: ExportMisc.uniqueLevelCaps,
|
uniqueLevelCaps: ExportMisc.uniqueLevelCaps,
|
||||||
Suits: [],
|
Suits: [],
|
||||||
LongGuns: [],
|
LongGuns: [],
|
||||||
@ -86,7 +85,8 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
QuestKeys: [],
|
QuestKeys: [],
|
||||||
KubrowPets: [],
|
KubrowPets: [],
|
||||||
EvolutionProgress: [],
|
EvolutionProgress: [],
|
||||||
mods: []
|
mods: [],
|
||||||
|
Boosters: []
|
||||||
};
|
};
|
||||||
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
|
for (const [uniqueName, item] of Object.entries(ExportWarframes)) {
|
||||||
res[item.productCategory].push({
|
res[item.productCategory].push({
|
||||||
@ -296,6 +296,13 @@ const getItemListsController: RequestHandler = (req, response) => {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for (const item of Object.values(ExportBoosters)) {
|
||||||
|
res.Boosters.push({
|
||||||
|
uniqueName: item.typeName,
|
||||||
|
name: getString(item.name, lang)
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
response.json(res);
|
response.json(res);
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -12,6 +12,7 @@ export const popArchonCrystalUpgradeController: RequestHandler = async (req, res
|
|||||||
);
|
);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.end();
|
res.end();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
res.status(400).end();
|
res.status(400).end();
|
||||||
};
|
};
|
||||||
|
@ -15,6 +15,7 @@ export const pushArchonCrystalUpgradeController: RequestHandler = async (req, re
|
|||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.end();
|
res.end();
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
res.status(400).end();
|
res.status(400).end();
|
||||||
|
45
src/controllers/custom/setBoosterController.ts
Normal file
45
src/controllers/custom/setBoosterController.ts
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { ExportBoosters } from "warframe-public-export-plus";
|
||||||
|
|
||||||
|
const I32_MAX = 0x7fffffff;
|
||||||
|
|
||||||
|
export const setBoosterController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const requests = req.body as { ItemType: string; ExpiryDate: number }[];
|
||||||
|
const inventory = await getInventory(accountId, "Boosters");
|
||||||
|
const boosters = inventory.Boosters;
|
||||||
|
if (
|
||||||
|
requests.some(request => {
|
||||||
|
if (typeof request.ItemType !== "string") return true;
|
||||||
|
if (Object.entries(ExportBoosters).find(([_, item]) => item.typeName === request.ItemType) === undefined)
|
||||||
|
return true;
|
||||||
|
if (typeof request.ExpiryDate !== "number") return true;
|
||||||
|
if (request.ExpiryDate < 0 || request.ExpiryDate > I32_MAX) return true;
|
||||||
|
return false;
|
||||||
|
})
|
||||||
|
) {
|
||||||
|
res.status(400).send("Invalid ItemType provided.");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
for (const { ItemType, ExpiryDate } of requests) {
|
||||||
|
if (ExpiryDate < now) {
|
||||||
|
// remove expired boosters
|
||||||
|
const index = boosters.findIndex(item => item.ItemType === ItemType);
|
||||||
|
if (index !== -1) {
|
||||||
|
boosters.splice(index, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const boosterItem = boosters.find(item => item.ItemType === ItemType);
|
||||||
|
if (boosterItem) {
|
||||||
|
boosterItem.ExpiryDate = ExpiryDate;
|
||||||
|
} else {
|
||||||
|
boosters.push({ ItemType, ExpiryDate });
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
await inventory.save();
|
||||||
|
res.end();
|
||||||
|
};
|
@ -1,15 +1,21 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { updateConfig } from "@/src/services/configWatcherService";
|
import { saveConfig } from "@/src/services/configWatcherService";
|
||||||
import { getAccountForRequest, isAdministrator } from "@/src/services/loginService";
|
import { getAccountForRequest, isAdministrator } from "@/src/services/loginService";
|
||||||
|
import { config, IConfig } from "@/src/services/configService";
|
||||||
|
|
||||||
const updateConfigDataController: RequestHandler = async (req, res) => {
|
export const updateConfigDataController: RequestHandler = async (req, res) => {
|
||||||
const account = await getAccountForRequest(req);
|
const account = await getAccountForRequest(req);
|
||||||
if (isAdministrator(account)) {
|
if (isAdministrator(account)) {
|
||||||
await updateConfig(String(req.body));
|
const data = req.body as IUpdateConfigDataRequest;
|
||||||
|
config[data.key] = data.value;
|
||||||
|
await saveConfig();
|
||||||
res.end();
|
res.end();
|
||||||
} else {
|
} else {
|
||||||
res.status(401).end();
|
res.status(401).end();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export { updateConfigDataController };
|
interface IUpdateConfigDataRequest {
|
||||||
|
key: keyof IConfig;
|
||||||
|
value: never;
|
||||||
|
}
|
||||||
|
@ -248,7 +248,7 @@ const requiemMods: readonly string[] = [
|
|||||||
"/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod"
|
"/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod"
|
||||||
];
|
];
|
||||||
|
|
||||||
const antivirusMods: readonly string[] = [
|
export const antivirusMods: readonly string[] = [
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod",
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod",
|
||||||
"/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod",
|
"/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod",
|
||||||
|
@ -10,3 +10,14 @@ export const getMaxStanding = (syndicate: ISyndicate, title: number): number =>
|
|||||||
}
|
}
|
||||||
return syndicate.titles.find(x => x.level == title)!.maxStanding;
|
return syndicate.titles.find(x => x.level == title)!.maxStanding;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const getMinStanding = (syndicate: ISyndicate, title: number): number => {
|
||||||
|
if (!syndicate.titles) {
|
||||||
|
// LibrarySyndicate
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if (title == 0) {
|
||||||
|
return syndicate.titles.find(x => x.level == -1)!.maxStanding;
|
||||||
|
}
|
||||||
|
return syndicate.titles.find(x => x.level == title)!.minStanding;
|
||||||
|
};
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
// First, init config.
|
// First, init config.
|
||||||
import { config, loadConfig } from "@/src/services/configService";
|
import { config, configPath, loadConfig } from "@/src/services/configService";
|
||||||
|
import fs from "fs";
|
||||||
try {
|
try {
|
||||||
loadConfig();
|
loadConfig();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("ERROR: Failed to load config.json. You can copy config.json.example to create your config.json.");
|
if (fs.existsSync("config.json")) {
|
||||||
|
console.log("Failed to load " + configPath + ": " + (e as Error).message);
|
||||||
|
} else {
|
||||||
|
console.log("Failed to load " + configPath + ". You can copy config.json.example to create your config file.");
|
||||||
|
}
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -251,12 +251,6 @@ const ArchonCrystalUpgradeSchema = new Schema<IArchonCrystalUpgrade>(
|
|||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
ArchonCrystalUpgradeSchema.set("toJSON", {
|
|
||||||
transform(_document, returnedObject) {
|
|
||||||
delete returnedObject.__v;
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
const boosterSchema = new Schema<IBooster>(
|
const boosterSchema = new Schema<IBooster>(
|
||||||
{
|
{
|
||||||
ExpiryDate: Number,
|
ExpiryDate: Number,
|
||||||
@ -1079,6 +1073,11 @@ EquipmentSchema.set("toJSON", {
|
|||||||
if (db.UmbraDate) {
|
if (db.UmbraDate) {
|
||||||
client.UmbraDate = toMongoDate(db.UmbraDate);
|
client.UmbraDate = toMongoDate(db.UmbraDate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (client.ArchonCrystalUpgrades) {
|
||||||
|
// For some reason, mongoose turns empty objects here into nulls, so we have to fix it.
|
||||||
|
client.ArchonCrystalUpgrades = client.ArchonCrystalUpgrades.map(x => (x as unknown) ?? {});
|
||||||
|
}
|
||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
@ -1704,7 +1703,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
LastInventorySync: Schema.Types.ObjectId,
|
LastInventorySync: Schema.Types.ObjectId,
|
||||||
Mailbox: MailboxSchema,
|
Mailbox: MailboxSchema,
|
||||||
HandlerPoints: Number,
|
HandlerPoints: Number,
|
||||||
ChallengesFixVersion: { type: Number, default: 6 },
|
ChallengesFixVersion: Number,
|
||||||
PlayedParkourTutorial: Boolean,
|
PlayedParkourTutorial: Boolean,
|
||||||
//ActiveLandscapeTraps: [Schema.Types.Mixed],
|
//ActiveLandscapeTraps: [Schema.Types.Mixed],
|
||||||
//RepVotes: [Schema.Types.Mixed],
|
//RepVotes: [Schema.Types.Mixed],
|
||||||
|
@ -33,6 +33,7 @@ import { createAllianceController } from "@/src/controllers/api/createAllianceCo
|
|||||||
import { createGuildController } from "@/src/controllers/api/createGuildController";
|
import { createGuildController } from "@/src/controllers/api/createGuildController";
|
||||||
import { creditsController } from "@/src/controllers/api/creditsController";
|
import { creditsController } from "@/src/controllers/api/creditsController";
|
||||||
import { crewMembersController } from "@/src/controllers/api/crewMembersController";
|
import { crewMembersController } from "@/src/controllers/api/crewMembersController";
|
||||||
|
import { crewShipFusionController } from "@/src/controllers/api/crewShipFusionController";
|
||||||
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
|
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
|
||||||
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
||||||
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
|
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
|
||||||
@ -132,6 +133,7 @@ import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDeco
|
|||||||
import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
|
import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController";
|
||||||
import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController";
|
import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController";
|
||||||
import { setShipVignetteController } from "@/src/controllers/api/setShipVignetteController";
|
import { setShipVignetteController } from "@/src/controllers/api/setShipVignetteController";
|
||||||
|
import { setSuitInfectionController } from "@/src/controllers/api/setSuitInfectionController";
|
||||||
import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
|
import { setSupportedSyndicateController } from "@/src/controllers/api/setSupportedSyndicateController";
|
||||||
import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController";
|
import { setWeaponSkillTreeController } from "@/src/controllers/api/setWeaponSkillTreeController";
|
||||||
import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController";
|
import { shipDecorationsController } from "@/src/controllers/api/shipDecorationsController";
|
||||||
@ -147,6 +149,7 @@ import { syndicateStandingBonusController } from "@/src/controllers/api/syndicat
|
|||||||
import { tauntHistoryController } from "@/src/controllers/api/tauntHistoryController";
|
import { tauntHistoryController } from "@/src/controllers/api/tauntHistoryController";
|
||||||
import { tradingController } from "@/src/controllers/api/tradingController";
|
import { tradingController } from "@/src/controllers/api/tradingController";
|
||||||
import { trainingResultController } from "@/src/controllers/api/trainingResultController";
|
import { trainingResultController } from "@/src/controllers/api/trainingResultController";
|
||||||
|
import { umbraController } from "@/src/controllers/api/umbraController";
|
||||||
import { unlockShipFeatureController } from "@/src/controllers/api/unlockShipFeatureController";
|
import { unlockShipFeatureController } from "@/src/controllers/api/unlockShipFeatureController";
|
||||||
import { updateAlignmentController } from "@/src/controllers/api/updateAlignmentController";
|
import { updateAlignmentController } from "@/src/controllers/api/updateAlignmentController";
|
||||||
import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController";
|
import { updateChallengeProgressController } from "@/src/controllers/api/updateChallengeProgressController";
|
||||||
@ -245,6 +248,7 @@ apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
|||||||
apiRouter.post("/createAlliance.php", createAllianceController);
|
apiRouter.post("/createAlliance.php", createAllianceController);
|
||||||
apiRouter.post("/createGuild.php", createGuildController);
|
apiRouter.post("/createGuild.php", createGuildController);
|
||||||
apiRouter.post("/crewMembers.php", crewMembersController);
|
apiRouter.post("/crewMembers.php", crewMembersController);
|
||||||
|
apiRouter.post("/crewShipFusion.php", crewShipFusionController);
|
||||||
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
|
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
|
||||||
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
||||||
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
||||||
@ -317,6 +321,7 @@ apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController);
|
|||||||
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
|
apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController);
|
||||||
apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController);
|
apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController);
|
||||||
apiRouter.post("/setShipVignette.php", setShipVignetteController);
|
apiRouter.post("/setShipVignette.php", setShipVignetteController);
|
||||||
|
apiRouter.post("/setSuitInfection.php", setSuitInfectionController);
|
||||||
apiRouter.post("/setWeaponSkillTree.php", setWeaponSkillTreeController);
|
apiRouter.post("/setWeaponSkillTree.php", setWeaponSkillTreeController);
|
||||||
apiRouter.post("/shipDecorations.php", shipDecorationsController);
|
apiRouter.post("/shipDecorations.php", shipDecorationsController);
|
||||||
apiRouter.post("/startCollectibleEntry.php", startCollectibleEntryController);
|
apiRouter.post("/startCollectibleEntry.php", startCollectibleEntryController);
|
||||||
@ -327,6 +332,7 @@ apiRouter.post("/syndicateSacrifice.php", syndicateSacrificeController);
|
|||||||
apiRouter.post("/syndicateStandingBonus.php", syndicateStandingBonusController);
|
apiRouter.post("/syndicateStandingBonus.php", syndicateStandingBonusController);
|
||||||
apiRouter.post("/tauntHistory.php", tauntHistoryController);
|
apiRouter.post("/tauntHistory.php", tauntHistoryController);
|
||||||
apiRouter.post("/trainingResult.php", trainingResultController);
|
apiRouter.post("/trainingResult.php", trainingResultController);
|
||||||
|
apiRouter.post("/umbra.php", umbraController);
|
||||||
apiRouter.post("/unlockShipFeature.php", unlockShipFeatureController);
|
apiRouter.post("/unlockShipFeature.php", unlockShipFeatureController);
|
||||||
apiRouter.post("/updateAlignment.php", updateAlignmentController);
|
apiRouter.post("/updateAlignment.php", updateAlignmentController);
|
||||||
apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController);
|
apiRouter.post("/updateChallengeProgress.php", updateChallengeProgressController);
|
||||||
|
@ -23,6 +23,7 @@ import { setEvolutionProgressController } from "@/src/controllers/custom/setEvol
|
|||||||
|
|
||||||
import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
|
import { getConfigDataController } from "@/src/controllers/custom/getConfigDataController";
|
||||||
import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
|
import { updateConfigDataController } from "@/src/controllers/custom/updateConfigDataController";
|
||||||
|
import { setBoosterController } from "../controllers/custom/setBoosterController";
|
||||||
|
|
||||||
const customRouter = express.Router();
|
const customRouter = express.Router();
|
||||||
|
|
||||||
@ -46,6 +47,7 @@ customRouter.post("/addXp", addXpController);
|
|||||||
customRouter.post("/import", importController);
|
customRouter.post("/import", importController);
|
||||||
customRouter.post("/manageQuests", manageQuestsController);
|
customRouter.post("/manageQuests", manageQuestsController);
|
||||||
customRouter.post("/setEvolutionProgress", setEvolutionProgressController);
|
customRouter.post("/setEvolutionProgress", setEvolutionProgressController);
|
||||||
|
customRouter.post("/setBooster", setBoosterController);
|
||||||
|
|
||||||
customRouter.get("/config", getConfigDataController);
|
customRouter.get("/config", getConfigDataController);
|
||||||
customRouter.post("/config", updateConfigDataController);
|
customRouter.post("/config", updateConfigDataController);
|
||||||
|
@ -2,7 +2,7 @@ import fs from "fs";
|
|||||||
import path from "path";
|
import path from "path";
|
||||||
import { repoDir } from "@/src/helpers/pathHelper";
|
import { repoDir } from "@/src/helpers/pathHelper";
|
||||||
|
|
||||||
interface IConfig {
|
export interface IConfig {
|
||||||
mongodbUrl: string;
|
mongodbUrl: string;
|
||||||
logger: {
|
logger: {
|
||||||
files: boolean;
|
files: boolean;
|
||||||
@ -56,17 +56,23 @@ interface IConfig {
|
|||||||
noDojoResearchTime?: boolean;
|
noDojoResearchTime?: boolean;
|
||||||
fastClanAscension?: boolean;
|
fastClanAscension?: boolean;
|
||||||
spoofMasteryRank?: number;
|
spoofMasteryRank?: number;
|
||||||
|
nightwaveStandingMultiplier?: number;
|
||||||
worldState?: {
|
worldState?: {
|
||||||
creditBoost?: boolean;
|
creditBoost?: boolean;
|
||||||
affinityBoost?: boolean;
|
affinityBoost?: boolean;
|
||||||
resourceBoost?: boolean;
|
resourceBoost?: boolean;
|
||||||
starDays?: boolean;
|
starDays?: boolean;
|
||||||
lockTime?: number;
|
eidolonOverride?: string;
|
||||||
|
vallisOverride?: string;
|
||||||
nightwaveOverride?: 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 = {
|
export const config: IConfig = {
|
||||||
mongodbUrl: "mongodb://127.0.0.1:27017/openWF",
|
mongodbUrl: "mongodb://127.0.0.1:27017/openWF",
|
||||||
|
@ -9,11 +9,11 @@ fs.watchFile(configPath, () => {
|
|||||||
if (amnesia) {
|
if (amnesia) {
|
||||||
amnesia = false;
|
amnesia = false;
|
||||||
} else {
|
} else {
|
||||||
logger.info("Detected a change to config.json, reloading its contents.");
|
logger.info("Detected a change to config file, reloading its contents.");
|
||||||
try {
|
try {
|
||||||
loadConfig();
|
loadConfig();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("Failed to reload config.json. Did you delete it?! Execution cannot continue.");
|
logger.error("FATAL ERROR: Config failed to be reloaded: " + (e as Error).message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
validateConfig();
|
validateConfig();
|
||||||
@ -41,17 +41,11 @@ export const validateConfig = (): void => {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (modified) {
|
if (modified) {
|
||||||
logger.info(`Updating config.json to fix some issues with it.`);
|
logger.info(`Updating config file to fix some issues with it.`);
|
||||||
void saveConfig();
|
void saveConfig();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
export const updateConfig = async (data: string): Promise<void> => {
|
|
||||||
amnesia = true;
|
|
||||||
await fsPromises.writeFile(configPath, data);
|
|
||||||
Object.assign(config, JSON.parse(data));
|
|
||||||
};
|
|
||||||
|
|
||||||
export const saveConfig = async (): Promise<void> => {
|
export const saveConfig = async (): Promise<void> => {
|
||||||
amnesia = true;
|
amnesia = true;
|
||||||
await fsPromises.writeFile(configPath, JSON.stringify(config, null, 2));
|
await fsPromises.writeFile(configPath, JSON.stringify(config, null, 2));
|
||||||
|
@ -50,14 +50,17 @@ export const createNewEventMessages = async (req: Request): Promise<void> => {
|
|||||||
await account.save();
|
await account.save();
|
||||||
};
|
};
|
||||||
|
|
||||||
export const createMessage = async (accountId: string | Types.ObjectId, messages: IMessageCreationTemplate[]) => {
|
export const createMessage = async (
|
||||||
|
accountId: string | Types.ObjectId,
|
||||||
|
messages: IMessageCreationTemplate[]
|
||||||
|
): Promise<HydratedDocument<IMessageDatabase>[]> => {
|
||||||
const ownerIdMessages = messages.map(m => ({
|
const ownerIdMessages = messages.map(m => ({
|
||||||
...m,
|
...m,
|
||||||
ownerId: accountId
|
ownerId: accountId
|
||||||
}));
|
}));
|
||||||
|
|
||||||
const savedMessages = await Inbox.insertMany(ownerIdMessages);
|
const savedMessages = await Inbox.insertMany(ownerIdMessages);
|
||||||
return savedMessages;
|
return savedMessages as HydratedDocument<IMessageDatabase>[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IMessageCreationTemplate extends Omit<IMessageDatabase, "_id" | "date" | "ownerId"> {
|
export interface IMessageCreationTemplate extends Omit<IMessageDatabase, "_id" | "date" | "ownerId"> {
|
||||||
|
@ -82,7 +82,7 @@ import { handleBundleAcqusition } from "./purchaseService";
|
|||||||
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
||||||
import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService";
|
import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService";
|
||||||
import { createMessage } from "./inboxService";
|
import { createMessage } from "./inboxService";
|
||||||
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
|
import { getMaxStanding, getMinStanding } from "@/src/helpers/syndicateStandingHelper";
|
||||||
import { getNightwaveSyndicateTag, getWorldState } from "./worldStateService";
|
import { getNightwaveSyndicateTag, getWorldState } from "./worldStateService";
|
||||||
import { generateNemesisProfile, INemesisProfile } from "../helpers/nemesisHelpers";
|
import { generateNemesisProfile, INemesisProfile } from "../helpers/nemesisHelpers";
|
||||||
import { TAccountDocument } from "./loginService";
|
import { TAccountDocument } from "./loginService";
|
||||||
@ -1202,8 +1202,10 @@ export const addStanding = (
|
|||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
syndicateTag: string,
|
syndicateTag: string,
|
||||||
gainedStanding: number,
|
gainedStanding: number,
|
||||||
isMedallion: boolean = false
|
affiliationMods: IAffiliationMods[] = [],
|
||||||
): IAffiliationMods => {
|
isMedallion: boolean = false,
|
||||||
|
propagateAlignments: boolean = true
|
||||||
|
): void => {
|
||||||
let syndicate = inventory.Affiliations.find(x => x.Tag == syndicateTag);
|
let syndicate = inventory.Affiliations.find(x => x.Tag == syndicateTag);
|
||||||
const syndicateMeta = ExportSyndicates[syndicateTag];
|
const syndicateMeta = ExportSyndicates[syndicateTag];
|
||||||
|
|
||||||
@ -1215,6 +1217,10 @@ export const addStanding = (
|
|||||||
const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0);
|
const max = getMaxStanding(syndicateMeta, syndicate.Title ?? 0);
|
||||||
if (syndicate.Standing + gainedStanding > max) gainedStanding = max - syndicate.Standing;
|
if (syndicate.Standing + gainedStanding > max) gainedStanding = max - syndicate.Standing;
|
||||||
|
|
||||||
|
if (syndicate.Title == -2 && syndicate.Standing + gainedStanding < -71000) {
|
||||||
|
gainedStanding = -71000 + syndicate.Standing;
|
||||||
|
}
|
||||||
|
|
||||||
if (!isMedallion || syndicateMeta.medallionsCappedByDailyLimit) {
|
if (!isMedallion || syndicateMeta.medallionsCappedByDailyLimit) {
|
||||||
if (gainedStanding > getStandingLimit(inventory, syndicateMeta.dailyLimitBin)) {
|
if (gainedStanding > getStandingLimit(inventory, syndicateMeta.dailyLimitBin)) {
|
||||||
gainedStanding = getStandingLimit(inventory, syndicateMeta.dailyLimitBin);
|
gainedStanding = getStandingLimit(inventory, syndicateMeta.dailyLimitBin);
|
||||||
@ -1223,10 +1229,27 @@ export const addStanding = (
|
|||||||
}
|
}
|
||||||
|
|
||||||
syndicate.Standing += gainedStanding;
|
syndicate.Standing += gainedStanding;
|
||||||
return {
|
const affiliationMod: IAffiliationMods = {
|
||||||
Tag: syndicateTag,
|
Tag: syndicateTag,
|
||||||
Standing: gainedStanding
|
Standing: gainedStanding
|
||||||
};
|
};
|
||||||
|
affiliationMods.push(affiliationMod);
|
||||||
|
|
||||||
|
if (syndicateMeta.alignments) {
|
||||||
|
if (propagateAlignments) {
|
||||||
|
for (const [tag, factor] of Object.entries(syndicateMeta.alignments)) {
|
||||||
|
addStanding(inventory, tag, gainedStanding * factor, affiliationMods, isMedallion, false);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
while (syndicate.Standing < getMinStanding(syndicateMeta, syndicate.Title ?? 0)) {
|
||||||
|
syndicate.Title ??= 0;
|
||||||
|
syndicate.Title -= 1;
|
||||||
|
affiliationMod.Title ??= 0;
|
||||||
|
affiliationMod.Title -= 1;
|
||||||
|
logger.debug(`${syndicateTag} is decreasing to title ${syndicate.Title} after applying alignment`);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
// TODO: AffiliationMods support (Nightwave).
|
// TODO: AffiliationMods support (Nightwave).
|
||||||
@ -1525,7 +1548,8 @@ export const applyClientEquipmentUpdates = (
|
|||||||
gearArray.forEach(({ ItemId, XP, InfestationDate }) => {
|
gearArray.forEach(({ ItemId, XP, InfestationDate }) => {
|
||||||
const item = category.id(fromOid(ItemId));
|
const item = category.id(fromOid(ItemId));
|
||||||
if (!item) {
|
if (!item) {
|
||||||
throw new Error(`No item with id ${fromOid(ItemId)} in ${categoryName}`);
|
logger.warn(`Skipping unknown ${categoryName} item: id ${fromOid(ItemId)} not found`);
|
||||||
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (XP) {
|
if (XP) {
|
||||||
@ -1556,7 +1580,7 @@ export const addMiscItem = (
|
|||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
type: string,
|
type: string,
|
||||||
count: number,
|
count: number,
|
||||||
inventoryChanges: IInventoryChanges
|
inventoryChanges: IInventoryChanges = {}
|
||||||
): void => {
|
): void => {
|
||||||
const miscItemChanges: IMiscItem[] = [
|
const miscItemChanges: IMiscItem[] = [
|
||||||
{
|
{
|
||||||
@ -1707,12 +1731,27 @@ export const addFocusXpIncreases = (inventory: TInventoryDatabaseDocument, focus
|
|||||||
AP_ANY
|
AP_ANY
|
||||||
}
|
}
|
||||||
|
|
||||||
inventory.FocusXP ??= { AP_ATTACK: 0, AP_DEFENSE: 0, AP_TACTIC: 0, AP_POWER: 0, AP_WARD: 0 };
|
inventory.FocusXP ??= {};
|
||||||
|
if (focusXpPlus[FocusType.AP_ATTACK]) {
|
||||||
|
inventory.FocusXP.AP_ATTACK ??= 0;
|
||||||
inventory.FocusXP.AP_ATTACK += focusXpPlus[FocusType.AP_ATTACK];
|
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];
|
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];
|
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];
|
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];
|
inventory.FocusXP.AP_WARD += focusXpPlus[FocusType.AP_WARD];
|
||||||
|
}
|
||||||
|
|
||||||
if (!config.noDailyFocusLimit) {
|
if (!config.noDailyFocusLimit) {
|
||||||
inventory.DailyFocus -= focusXpPlus.reduce((a, b) => a + b, 0);
|
inventory.DailyFocus -= focusXpPlus.reduce((a, b) => a + b, 0);
|
||||||
@ -1772,13 +1811,14 @@ export const addChallenges = (
|
|||||||
}) - 1
|
}) - 1
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
affiliation.Standing += meta.standing!;
|
|
||||||
|
|
||||||
|
const standingToAdd = meta.standing! * (config.nightwaveStandingMultiplier ?? 1);
|
||||||
|
affiliation.Standing += standingToAdd;
|
||||||
if (affiliationMods.length == 0) {
|
if (affiliationMods.length == 0) {
|
||||||
affiliationMods.push({ Tag: nightwaveSyndicateTag });
|
affiliationMods.push({ Tag: nightwaveSyndicateTag });
|
||||||
}
|
}
|
||||||
affiliationMods[0].Standing ??= 0;
|
affiliationMods[0].Standing ??= 0;
|
||||||
affiliationMods[0].Standing += meta.standing!;
|
affiliationMods[0].Standing += standingToAdd;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -233,7 +233,7 @@ export const isStoreItem = (type: string): boolean => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const toStoreItem = (type: string): string => {
|
export const toStoreItem = (type: string): string => {
|
||||||
if (type.startsWith("/Lotus/Types/StoreItems/Boosters/")) {
|
if (type.startsWith("/Lotus/Types/Boosters/")) {
|
||||||
const boosterEntry = Object.entries(ExportBoosters).find(arr => arr[1].typeName == type);
|
const boosterEntry = Object.entries(ExportBoosters).find(arr => arr[1].typeName == type);
|
||||||
if (boosterEntry) {
|
if (boosterEntry) {
|
||||||
return boosterEntry[0];
|
return boosterEntry[0];
|
||||||
|
@ -66,15 +66,7 @@ import {
|
|||||||
} from "@/src/helpers/nemesisHelpers";
|
} from "@/src/helpers/nemesisHelpers";
|
||||||
import { Loadout } from "../models/inventoryModels/loadoutModel";
|
import { Loadout } from "../models/inventoryModels/loadoutModel";
|
||||||
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
|
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
|
||||||
import {
|
import { getLiteSortie, getSortie, idToBountyCycle, idToDay, idToWeek, pushClassicBounties } from "./worldStateService";
|
||||||
getLiteSortie,
|
|
||||||
getSortie,
|
|
||||||
getWorldState,
|
|
||||||
idToBountyCycle,
|
|
||||||
idToDay,
|
|
||||||
idToWeek,
|
|
||||||
pushClassicBounties
|
|
||||||
} from "./worldStateService";
|
|
||||||
import { config } from "./configService";
|
import { config } from "./configService";
|
||||||
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
||||||
import { ISyndicateMissionInfo } from "../types/worldStateTypes";
|
import { ISyndicateMissionInfo } from "../types/worldStateTypes";
|
||||||
@ -1236,19 +1228,18 @@ export const addMissionRewards = async (
|
|||||||
SyndicateXPItemReward = medallionAmount;
|
SyndicateXPItemReward = medallionAmount;
|
||||||
} else {
|
} else {
|
||||||
if (rewardInfo.JobTier! >= 0) {
|
if (rewardInfo.JobTier! >= 0) {
|
||||||
AffiliationMods.push(
|
|
||||||
addStanding(
|
addStanding(
|
||||||
inventory,
|
inventory,
|
||||||
syndicateEntry.Tag,
|
syndicateEntry.Tag,
|
||||||
Math.floor(currentJob.xpAmounts[rewardInfo.JobStage] / (rewardInfo.Q ? 0.8 : 1))
|
Math.floor(currentJob.xpAmounts[rewardInfo.JobStage] / (rewardInfo.Q ? 0.8 : 1)),
|
||||||
)
|
AffiliationMods
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
if (jobType.endsWith("Heists/HeistProfitTakerBountyOne") && rewardInfo.JobStage === 2) {
|
if (jobType.endsWith("Heists/HeistProfitTakerBountyOne") && rewardInfo.JobStage === 2) {
|
||||||
AffiliationMods.push(addStanding(inventory, syndicateEntry.Tag, 1000));
|
addStanding(inventory, syndicateEntry.Tag, 1000, AffiliationMods);
|
||||||
}
|
}
|
||||||
if (jobType.endsWith("Hunts/AllTeralystsHunt") && rewardInfo.JobStage === 2) {
|
if (jobType.endsWith("Hunts/AllTeralystsHunt") && rewardInfo.JobStage === 2) {
|
||||||
AffiliationMods.push(addStanding(inventory, syndicateEntry.Tag, 5000));
|
addStanding(inventory, syndicateEntry.Tag, 5000, AffiliationMods);
|
||||||
}
|
}
|
||||||
if (
|
if (
|
||||||
[
|
[
|
||||||
@ -1259,7 +1250,7 @@ export const addMissionRewards = async (
|
|||||||
"Heists/HeistExploiterBountyOne"
|
"Heists/HeistExploiterBountyOne"
|
||||||
].some(ending => jobType.endsWith(ending))
|
].some(ending => jobType.endsWith(ending))
|
||||||
) {
|
) {
|
||||||
AffiliationMods.push(addStanding(inventory, syndicateEntry.Tag, 1000));
|
addStanding(inventory, syndicateEntry.Tag, 1000, AffiliationMods);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1267,9 +1258,9 @@ export const addMissionRewards = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rewardInfo.challengeMissionId) {
|
if (rewardInfo.challengeMissionId) {
|
||||||
const [syndicateTag, tierStr, chemistryStr] = rewardInfo.challengeMissionId.split("_");
|
const [syndicateTag, tierStr, chemistryBuddyStr] = rewardInfo.challengeMissionId.split("_");
|
||||||
const tier = Number(tierStr);
|
const tier = Number(tierStr);
|
||||||
const chemistry = Number(chemistryStr);
|
const chemistryBuddy = Number(chemistryBuddyStr);
|
||||||
const isSteelPath = missions?.Tier;
|
const isSteelPath = missions?.Tier;
|
||||||
if (syndicateTag === "ZarimanSyndicate") {
|
if (syndicateTag === "ZarimanSyndicate") {
|
||||||
let medallionAmount = tier + 1;
|
let medallionAmount = tier + 1;
|
||||||
@ -1284,24 +1275,21 @@ export const addMissionRewards = async (
|
|||||||
let standingAmount = (tier + 1) * 1000;
|
let standingAmount = (tier + 1) * 1000;
|
||||||
if (tier > 5) standingAmount = 7500; // InfestedLichBounty
|
if (tier > 5) standingAmount = 7500; // InfestedLichBounty
|
||||||
if (isSteelPath) standingAmount *= 1.5;
|
if (isSteelPath) standingAmount *= 1.5;
|
||||||
AffiliationMods.push(addStanding(inventory, syndicateTag, standingAmount));
|
addStanding(inventory, syndicateTag, standingAmount, AffiliationMods);
|
||||||
}
|
|
||||||
if (syndicateTag == "HexSyndicate" && chemistry && tier < 6) {
|
|
||||||
const seed = getWorldState().SyndicateMissions.find(x => x.Tag == "HexSyndicate")!.Seed;
|
|
||||||
const { nodes, buddies } = getHexBounties(seed);
|
|
||||||
const buddy = buddies[tier];
|
|
||||||
logger.debug(`Hex seed is ${seed}, giving chemistry for ${buddy}`);
|
|
||||||
if (missions?.Tag != nodes[tier]) {
|
|
||||||
logger.warn(
|
|
||||||
`Uh-oh, tier ${tier} bounty should've been on ${nodes[tier]} but you were just on ${missions?.Tag}`
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
if (syndicateTag == "HexSyndicate" && tier < 6) {
|
||||||
|
const buddy = chemistryBuddies[chemistryBuddy];
|
||||||
|
const dialogue = getDialogue(inventory, buddy);
|
||||||
|
if (Date.now() >= dialogue.BountyChemExpiry.getTime()) {
|
||||||
|
logger.debug(`Giving 20 chemistry for ${buddy}`);
|
||||||
const tomorrowAt0Utc = config.noKimCooldowns
|
const tomorrowAt0Utc = config.noKimCooldowns
|
||||||
? Date.now()
|
? Date.now()
|
||||||
: (Math.trunc(Date.now() / 86400_000) + 1) * 86400_000;
|
: (Math.trunc(Date.now() / 86400_000) + 1) * 86400_000;
|
||||||
const dialogue = getDialogue(inventory, buddy);
|
dialogue.Chemistry += 20;
|
||||||
dialogue.Chemistry += chemistry;
|
|
||||||
dialogue.BountyChemExpiry = new Date(tomorrowAt0Utc);
|
dialogue.BountyChemExpiry = new Date(tomorrowAt0Utc);
|
||||||
|
} else {
|
||||||
|
logger.debug(`Already got today's chemistry for ${buddy}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isSteelPath) {
|
if (isSteelPath) {
|
||||||
await addItem(inventory, "/Lotus/Types/Items/MiscItems/SteelEssence", 1);
|
await addItem(inventory, "/Lotus/Types/Items/MiscItems/SteelEssence", 1);
|
||||||
@ -1865,7 +1853,16 @@ const libraryPersonalTargetToAvatar: Record<string, string> = {
|
|||||||
"/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/NullifySpacemanAvatar"
|
"/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/NullifySpacemanAvatar"
|
||||||
};
|
};
|
||||||
|
|
||||||
const node_excluded_buddies: Record<string, string> = {
|
const chemistryBuddies: readonly string[] = [
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue",
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/AoiDialogue_rom.dialogue",
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue",
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/EleanorDialogue_rom.dialogue",
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue",
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/QuincyDialogue_rom.dialogue"
|
||||||
|
];
|
||||||
|
|
||||||
|
/*const node_excluded_buddies: Record<string, string> = {
|
||||||
SolNode856: "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue",
|
SolNode856: "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue",
|
||||||
SolNode852: "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue",
|
SolNode852: "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue",
|
||||||
SolNode851: "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue",
|
SolNode851: "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue",
|
||||||
@ -1915,4 +1912,4 @@ const getHexBounties = (seed: number): { nodes: string[]; buddies: string[] } =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { nodes, buddies };
|
return { nodes, buddies };
|
||||||
};
|
};*/
|
||||||
|
@ -3,10 +3,9 @@ import { isDev } from "@/src/helpers/pathHelper";
|
|||||||
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
import { catBreadHash } from "@/src/helpers/stringHelpers";
|
||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { mixSeeds, SRng } from "@/src/services/rngService";
|
import { mixSeeds, SRng } from "@/src/services/rngService";
|
||||||
import { IMongoDate } from "@/src/types/commonTypes";
|
|
||||||
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
|
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { ExportVendors, IRange, IVendor } from "warframe-public-export-plus";
|
import { ExportVendors, IRange, IVendor, IVendorOffer } from "warframe-public-export-plus";
|
||||||
|
|
||||||
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
||||||
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
|
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
|
||||||
@ -17,20 +16,14 @@ import DeimosHivemindCommisionsManifestTokenVendor from "@/static/fixed_response
|
|||||||
import DeimosHivemindCommisionsManifestWeaponsmith from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestWeaponsmith.json";
|
import DeimosHivemindCommisionsManifestWeaponsmith from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestWeaponsmith.json";
|
||||||
import DeimosHivemindTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosHivemindTokenVendorManifest.json";
|
import DeimosHivemindTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosHivemindTokenVendorManifest.json";
|
||||||
import DeimosPetVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosPetVendorManifest.json";
|
import DeimosPetVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosPetVendorManifest.json";
|
||||||
import DeimosProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosProspectorVendorManifest.json";
|
|
||||||
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
|
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
|
||||||
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
|
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
|
||||||
import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
|
import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
|
||||||
import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsIronwakeDondaVendorManifest.json";
|
|
||||||
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
|
|
||||||
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
|
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
|
||||||
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
|
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
|
||||||
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
|
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
|
||||||
import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json";
|
|
||||||
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
|
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
|
||||||
import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json";
|
|
||||||
import Temple1999VendorManifest from "@/static/fixed_responses/getVendorInfo/Temple1999VendorManifest.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";
|
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
||||||
|
|
||||||
const rawVendorManifests: IVendorManifest[] = [
|
const rawVendorManifests: IVendorManifest[] = [
|
||||||
@ -43,20 +36,14 @@ const rawVendorManifests: IVendorManifest[] = [
|
|||||||
DeimosHivemindCommisionsManifestWeaponsmith,
|
DeimosHivemindCommisionsManifestWeaponsmith,
|
||||||
DeimosHivemindTokenVendorManifest,
|
DeimosHivemindTokenVendorManifest,
|
||||||
DeimosPetVendorManifest,
|
DeimosPetVendorManifest,
|
||||||
DeimosProspectorVendorManifest,
|
|
||||||
DuviriAcrithisVendorManifest,
|
DuviriAcrithisVendorManifest,
|
||||||
EntratiLabsEntratiLabsCommisionsManifest,
|
EntratiLabsEntratiLabsCommisionsManifest,
|
||||||
EntratiLabsEntratiLabVendorManifest,
|
EntratiLabsEntratiLabVendorManifest,
|
||||||
HubsIronwakeDondaVendorManifest, // uses preprocessing
|
|
||||||
HubsRailjackCrewMemberVendorManifest,
|
|
||||||
MaskSalesmanManifest,
|
MaskSalesmanManifest,
|
||||||
Nova1999ConquestShopManifest,
|
Nova1999ConquestShopManifest,
|
||||||
OstronPetVendorManifest,
|
OstronPetVendorManifest,
|
||||||
OstronProspectorVendorManifest,
|
|
||||||
SolarisDebtTokenVendorRepossessionsManifest,
|
SolarisDebtTokenVendorRepossessionsManifest,
|
||||||
SolarisProspectorVendorManifest,
|
|
||||||
Temple1999VendorManifest,
|
Temple1999VendorManifest,
|
||||||
TeshinHardModeVendorManifest, // uses preprocessing
|
|
||||||
ZarimanCommisionsManifestArchimedean
|
ZarimanCommisionsManifestArchimedean
|
||||||
];
|
];
|
||||||
|
|
||||||
@ -83,10 +70,6 @@ const generatableVendors: IGeneratableVendorInfo[] = [
|
|||||||
cycleOffset: 1744934400_000,
|
cycleOffset: 1744934400_000,
|
||||||
cycleDuration: 4 * unixTimesInMs.day
|
cycleDuration: 4 * unixTimesInMs.day
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// _id: { $oid: "5dbb4c41e966f7886c3ce939" },
|
|
||||||
// TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest"
|
|
||||||
// }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const getVendorOid = (typeName: string): string => {
|
const getVendorOid = (typeName: string): string => {
|
||||||
@ -101,12 +84,16 @@ const gcd = (a: number, b: number): number => {
|
|||||||
const getCycleDuration = (manifest: IVendor): number => {
|
const getCycleDuration = (manifest: IVendor): number => {
|
||||||
let dur = 0;
|
let dur = 0;
|
||||||
for (const item of manifest.items) {
|
for (const item of manifest.items) {
|
||||||
if (typeof item.durationHours != "number") {
|
if (item.alwaysOffered) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
const durationHours = item.rotatedWeekly ? 168 : item.durationHours;
|
||||||
|
if (typeof durationHours != "number") {
|
||||||
dur = 1;
|
dur = 1;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
if (dur != item.durationHours) {
|
if (dur != durationHours) {
|
||||||
dur = gcd(dur, item.durationHours);
|
dur = gcd(dur, durationHours);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return dur * unixTimesInMs.hour;
|
return dur * unixTimesInMs.hour;
|
||||||
@ -115,7 +102,7 @@ const getCycleDuration = (manifest: IVendor): number => {
|
|||||||
export const getVendorManifestByTypeName = (typeName: string): IVendorManifest | undefined => {
|
export const getVendorManifestByTypeName = (typeName: string): IVendorManifest | undefined => {
|
||||||
for (const vendorManifest of rawVendorManifests) {
|
for (const vendorManifest of rawVendorManifests) {
|
||||||
if (vendorManifest.VendorInfo.TypeName == typeName) {
|
if (vendorManifest.VendorInfo.TypeName == typeName) {
|
||||||
return preprocessVendorManifest(vendorManifest);
|
return vendorManifest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const vendorInfo of generatableVendors) {
|
for (const vendorInfo of generatableVendors) {
|
||||||
@ -138,7 +125,7 @@ export const getVendorManifestByTypeName = (typeName: string): IVendorManifest |
|
|||||||
export const getVendorManifestByOid = (oid: string): IVendorManifest | undefined => {
|
export const getVendorManifestByOid = (oid: string): IVendorManifest | undefined => {
|
||||||
for (const vendorManifest of rawVendorManifests) {
|
for (const vendorManifest of rawVendorManifests) {
|
||||||
if (vendorManifest.VendorInfo._id.$oid == oid) {
|
if (vendorManifest.VendorInfo._id.$oid == oid) {
|
||||||
return preprocessVendorManifest(vendorManifest);
|
return vendorManifest;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (const vendorInfo of generatableVendors) {
|
for (const vendorInfo of generatableVendors) {
|
||||||
@ -197,30 +184,6 @@ export const applyStandingToVendorManifest = (
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
const preprocessVendorManifest = (originalManifest: IVendorManifest): IVendorManifest => {
|
|
||||||
if (Date.now() >= parseInt(originalManifest.VendorInfo.Expiry.$date.$numberLong)) {
|
|
||||||
const manifest = structuredClone(originalManifest);
|
|
||||||
const info = manifest.VendorInfo;
|
|
||||||
refreshExpiry(info.Expiry);
|
|
||||||
for (const offer of info.ItemManifest) {
|
|
||||||
refreshExpiry(offer.Expiry);
|
|
||||||
}
|
|
||||||
return manifest;
|
|
||||||
}
|
|
||||||
return originalManifest;
|
|
||||||
};
|
|
||||||
|
|
||||||
const refreshExpiry = (expiry: IMongoDate): void => {
|
|
||||||
const period = parseInt(expiry.$date.$numberLong);
|
|
||||||
if (Date.now() >= period) {
|
|
||||||
const epoch = 1734307200_000; // Monday (for weekly schedules)
|
|
||||||
const iteration = Math.trunc((Date.now() - epoch) / period);
|
|
||||||
const start = epoch + iteration * period;
|
|
||||||
const end = start + period;
|
|
||||||
expiry.$date.$numberLong = end.toString();
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
const toRange = (value: IRange | number): IRange => {
|
const toRange = (value: IRange | number): IRange => {
|
||||||
if (typeof value == "number") {
|
if (typeof value == "number") {
|
||||||
return { minValue: value, maxValue: value };
|
return { minValue: value, maxValue: value };
|
||||||
@ -228,6 +191,34 @@ const toRange = (value: IRange | number): IRange => {
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getCycleDurationRange = (manifest: IVendor): IRange | undefined => {
|
||||||
|
const res: IRange = { minValue: Number.MAX_SAFE_INTEGER, maxValue: 0 };
|
||||||
|
for (const offer of manifest.items) {
|
||||||
|
if (offer.durationHours) {
|
||||||
|
const range = toRange(offer.durationHours);
|
||||||
|
if (res.minValue > range.minValue) {
|
||||||
|
res.minValue = range.minValue;
|
||||||
|
}
|
||||||
|
if (res.maxValue < range.maxValue) {
|
||||||
|
res.maxValue = range.maxValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res.maxValue != 0 ? res : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
|
type TOfferId = string;
|
||||||
|
|
||||||
|
const getOfferId = (offer: IVendorOffer | IItemManifest): TOfferId => {
|
||||||
|
if ("storeItem" in offer) {
|
||||||
|
// IVendorOffer
|
||||||
|
return offer.storeItem + "x" + offer.quantity;
|
||||||
|
} else {
|
||||||
|
// IItemManifest
|
||||||
|
return offer.StoreItem + "x" + offer.QuantityMultiplier;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
const vendorManifestCache: Record<string, IVendorManifest> = {};
|
const vendorManifestCache: Record<string, IVendorManifest> = {};
|
||||||
|
|
||||||
const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifest => {
|
const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifest => {
|
||||||
@ -244,10 +235,16 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
}
|
}
|
||||||
const cacheEntry = vendorManifestCache[vendorInfo.TypeName];
|
const cacheEntry = vendorManifestCache[vendorInfo.TypeName];
|
||||||
const info = cacheEntry.VendorInfo;
|
const info = cacheEntry.VendorInfo;
|
||||||
if (Date.now() >= parseInt(info.Expiry.$date.$numberLong)) {
|
const manifest = ExportVendors[vendorInfo.TypeName];
|
||||||
|
const cycleDurationRange = getCycleDurationRange(manifest);
|
||||||
|
let now = Date.now();
|
||||||
|
if (cycleDurationRange && cycleDurationRange.minValue != cycleDurationRange.maxValue) {
|
||||||
|
now -= (cycleDurationRange.maxValue - 1) * unixTimesInMs.hour;
|
||||||
|
}
|
||||||
|
while (Date.now() >= parseInt(info.Expiry.$date.$numberLong)) {
|
||||||
// Remove expired offers
|
// Remove expired offers
|
||||||
for (let i = 0; i != info.ItemManifest.length; ) {
|
for (let i = 0; i != info.ItemManifest.length; ) {
|
||||||
if (Date.now() >= parseInt(info.ItemManifest[i].Expiry.$date.$numberLong)) {
|
if (now >= parseInt(info.ItemManifest[i].Expiry.$date.$numberLong)) {
|
||||||
info.ItemManifest.splice(i, 1);
|
info.ItemManifest.splice(i, 1);
|
||||||
} else {
|
} else {
|
||||||
++i;
|
++i;
|
||||||
@ -258,62 +255,101 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
const vendorSeed = parseInt(vendorInfo._id.$oid.substring(16), 16);
|
const vendorSeed = parseInt(vendorInfo._id.$oid.substring(16), 16);
|
||||||
const cycleOffset = vendorInfo.cycleOffset ?? 1734307200_000;
|
const cycleOffset = vendorInfo.cycleOffset ?? 1734307200_000;
|
||||||
const cycleDuration = vendorInfo.cycleDuration;
|
const cycleDuration = vendorInfo.cycleDuration;
|
||||||
const cycleIndex = Math.trunc((Date.now() - cycleOffset) / cycleDuration);
|
const cycleIndex = Math.trunc((now - cycleOffset) / cycleDuration);
|
||||||
const rng = new SRng(mixSeeds(vendorSeed, cycleIndex));
|
const rng = new SRng(mixSeeds(vendorSeed, cycleIndex));
|
||||||
const manifest = ExportVendors[vendorInfo.TypeName];
|
const offersToAdd: IVendorOffer[] = [];
|
||||||
const offersToAdd = [];
|
if (!manifest.isOneBinPerCycle) {
|
||||||
if (
|
// Compute vendor requirements, subtracting existing offers
|
||||||
manifest.numItems &&
|
const remainingItemCapacity: Record<TOfferId, number> = {};
|
||||||
(manifest.numItems.minValue != manifest.numItems.maxValue ||
|
const missingItemsPerBin: Record<number, number> = {};
|
||||||
manifest.items.length != manifest.numItems.minValue) &&
|
let numOffersThatNeedToMatchABin = 0;
|
||||||
!manifest.isOneBinPerCycle
|
if (manifest.numItemsPerBin) {
|
||||||
) {
|
for (let bin = 0; bin != manifest.numItemsPerBin.length; ++bin) {
|
||||||
const remainingItemCapacity: Record<string, number> = {};
|
missingItemsPerBin[bin] = manifest.numItemsPerBin[bin];
|
||||||
|
numOffersThatNeedToMatchABin += manifest.numItemsPerBin[bin];
|
||||||
|
}
|
||||||
|
}
|
||||||
for (const item of manifest.items) {
|
for (const item of manifest.items) {
|
||||||
remainingItemCapacity[item.storeItem] = 1 + item.duplicates;
|
remainingItemCapacity[getOfferId(item)] = 1 + item.duplicates;
|
||||||
}
|
}
|
||||||
for (const offer of info.ItemManifest) {
|
for (const offer of info.ItemManifest) {
|
||||||
remainingItemCapacity[offer.StoreItem] -= 1;
|
remainingItemCapacity[getOfferId(offer)] -= 1;
|
||||||
}
|
const bin = parseInt(offer.Bin.substring(4));
|
||||||
const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
|
if (missingItemsPerBin[bin]) {
|
||||||
while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) {
|
missingItemsPerBin[bin] -= 1;
|
||||||
// TODO: Consider per-bin item limits
|
numOffersThatNeedToMatchABin -= 1;
|
||||||
// TODO: Consider item probability weightings
|
|
||||||
const item = rng.randomElement(manifest.items)!;
|
|
||||||
if (remainingItemCapacity[item.storeItem] != 0) {
|
|
||||||
remainingItemCapacity[item.storeItem] -= 1;
|
|
||||||
offersToAdd.push(item);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
let binThisCycle;
|
|
||||||
if (manifest.isOneBinPerCycle) {
|
|
||||||
binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
|
|
||||||
}
|
|
||||||
for (const rawItem of manifest.items) {
|
|
||||||
if (!manifest.isOneBinPerCycle || rawItem.bin == binThisCycle) {
|
|
||||||
offersToAdd.push(rawItem);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For most vendors, the offers seem to roughly be in reverse order from the manifest. Coda weapons are an odd exception.
|
// Add permanent offers
|
||||||
if (!manifest.isOneBinPerCycle) {
|
let numUncountedOffers = 0;
|
||||||
offersToAdd.reverse();
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Add counted offers
|
||||||
|
if (manifest.numItems) {
|
||||||
|
const useRng = manifest.numItems.minValue != manifest.numItems.maxValue;
|
||||||
|
const numItemsTarget =
|
||||||
|
numUncountedOffers +
|
||||||
|
(useRng
|
||||||
|
? rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue)
|
||||||
|
: manifest.numItems.minValue);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
if (i == manifest.items.length) {
|
||||||
|
i = 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
|
||||||
|
for (const rawItem of manifest.items) {
|
||||||
|
if (rawItem.bin == binThisCycle) {
|
||||||
|
offersToAdd.push(rawItem);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
const cycleStart = cycleOffset + cycleIndex * cycleDuration;
|
const cycleStart = cycleOffset + cycleIndex * cycleDuration;
|
||||||
for (const rawItem of offersToAdd) {
|
for (const rawItem of offersToAdd) {
|
||||||
const durationHoursRange = toRange(rawItem.durationHours ?? cycleDuration);
|
const durationHoursRange = toRange(rawItem.durationHours ?? cycleDuration);
|
||||||
const expiry =
|
const expiry = rawItem.alwaysOffered
|
||||||
cycleStart +
|
? 2051240400_000
|
||||||
rng.randomInt(durationHoursRange.minValue, durationHoursRange.maxValue) * unixTimesInMs.hour;
|
: cycleStart +
|
||||||
|
(rawItem.rotatedWeekly
|
||||||
|
? unixTimesInMs.week
|
||||||
|
: rng.randomInt(durationHoursRange.minValue, durationHoursRange.maxValue) * unixTimesInMs.hour);
|
||||||
const item: IItemManifest = {
|
const item: IItemManifest = {
|
||||||
StoreItem: rawItem.storeItem,
|
StoreItem: rawItem.storeItem,
|
||||||
ItemPrices: rawItem.itemPrices?.map(itemPrice => ({ ...itemPrice, ProductCategory: "MiscItems" })),
|
ItemPrices: rawItem.itemPrices?.map(itemPrice => ({ ...itemPrice, ProductCategory: "MiscItems" })),
|
||||||
Bin: "BIN_" + rawItem.bin,
|
Bin: "BIN_" + rawItem.bin,
|
||||||
QuantityMultiplier: 1,
|
QuantityMultiplier: rawItem.quantity,
|
||||||
Expiry: { $date: { $numberLong: expiry.toString() } },
|
Expiry: { $date: { $numberLong: expiry.toString() } },
|
||||||
AllowMultipurchase: false,
|
PurchaseQuantityLimit: rawItem.purchaseLimit,
|
||||||
|
RotatedWeekly: rawItem.rotatedWeekly,
|
||||||
|
AllowMultipurchase: rawItem.purchaseLimit !== 1,
|
||||||
Id: {
|
Id: {
|
||||||
$oid:
|
$oid:
|
||||||
((cycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") +
|
((cycleStart / 1000) & 0xffffffff).toString(16).padStart(8, "0") +
|
||||||
@ -362,6 +398,12 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
info.ItemManifest.push(item);
|
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
|
// Update vendor expiry
|
||||||
let soonestOfferExpiry: number = Number.MAX_SAFE_INTEGER;
|
let soonestOfferExpiry: number = Number.MAX_SAFE_INTEGER;
|
||||||
for (const offer of info.ItemManifest) {
|
for (const offer of info.ItemManifest) {
|
||||||
@ -371,11 +413,20 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
info.Expiry.$date.$numberLong = soonestOfferExpiry.toString();
|
info.Expiry.$date.$numberLong = soonestOfferExpiry.toString();
|
||||||
|
|
||||||
|
now += unixTimesInMs.hour;
|
||||||
}
|
}
|
||||||
return cacheEntry;
|
return cacheEntry;
|
||||||
};
|
};
|
||||||
|
|
||||||
if (isDev) {
|
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")!
|
const ads = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest")!
|
||||||
.VendorInfo.ItemManifest;
|
.VendorInfo.ItemManifest;
|
||||||
if (
|
if (
|
||||||
@ -388,4 +439,30 @@ if (isDev) {
|
|||||||
) {
|
) {
|
||||||
logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest`);
|
logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pall = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest")!
|
||||||
|
.VendorInfo.ItemManifest;
|
||||||
|
if (
|
||||||
|
pall.length != 5 ||
|
||||||
|
pall[0].StoreItem != "/Lotus/StoreItems/Types/Items/ShipDecos/HarrowQuestKeyOrnament" ||
|
||||||
|
pall[1].StoreItem != "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack" ||
|
||||||
|
pall[2].StoreItem != "/Lotus/StoreItems/Types/StoreItems/CreditBundles/150000Credits" ||
|
||||||
|
pall[3].StoreItem != "/Lotus/StoreItems/Types/Items/MiscItems/Kuva" ||
|
||||||
|
pall[4].StoreItem != "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack"
|
||||||
|
) {
|
||||||
|
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`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -16,9 +16,13 @@ import {
|
|||||||
ISortie,
|
ISortie,
|
||||||
ISortieMission,
|
ISortieMission,
|
||||||
ISyndicateMissionInfo,
|
ISyndicateMissionInfo,
|
||||||
IWorldState
|
ITmp,
|
||||||
|
IVoidStorm,
|
||||||
|
IWorldState,
|
||||||
|
TCircuitGameMode
|
||||||
} from "../types/worldStateTypes";
|
} from "../types/worldStateTypes";
|
||||||
import { version_compare } from "../helpers/inventoryHelpers";
|
import { version_compare } from "../helpers/inventoryHelpers";
|
||||||
|
import { logger } from "../utils/logger";
|
||||||
|
|
||||||
const sortieBosses = [
|
const sortieBosses = [
|
||||||
"SORTIE_BOSS_HYENA",
|
"SORTIE_BOSS_HYENA",
|
||||||
@ -452,13 +456,37 @@ const pushWeeklyActs = (
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const generateXpAmounts = (rng: SRng, stageCount: number, minXp: number, maxXp: number): number[] => {
|
||||||
|
const step = minXp < 1000 ? 1 : 10;
|
||||||
|
const totalDeciXp = rng.randomInt(minXp / step, maxXp / step);
|
||||||
|
const xpAmounts: number[] = [];
|
||||||
|
if (stageCount < 4) {
|
||||||
|
const perStage = Math.ceil(totalDeciXp / stageCount) * step;
|
||||||
|
for (let i = 0; i != stageCount; ++i) {
|
||||||
|
xpAmounts.push(perStage);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const perStage = Math.ceil(Math.round(totalDeciXp * 0.667) / (stageCount - 1)) * step;
|
||||||
|
for (let i = 0; i != stageCount - 1; ++i) {
|
||||||
|
xpAmounts.push(perStage);
|
||||||
|
}
|
||||||
|
xpAmounts.push(Math.ceil(totalDeciXp * 0.332) * step);
|
||||||
|
}
|
||||||
|
return xpAmounts;
|
||||||
|
};
|
||||||
|
// Test vectors:
|
||||||
|
//console.log(generateXpAmounts(new SRng(1337n), 5, 5000, 5000)); // [840, 840, 840, 840, 1660]
|
||||||
|
//console.log(generateXpAmounts(new SRng(1337n), 3, 40, 40)); // [14, 14, 14]
|
||||||
|
//console.log(generateXpAmounts(new SRng(1337n), 5, 150, 150)); // [25, 25, 25, 25, 50]
|
||||||
|
//console.log(generateXpAmounts(new SRng(1337n), 4, 10, 10)); // [2, 2, 2, 4]
|
||||||
|
//console.log(generateXpAmounts(new SRng(1337n), 4, 15, 15)); // [4, 4, 4, 5]
|
||||||
|
//console.log(generateXpAmounts(new SRng(1337n), 4, 20, 20)); // [5, 5, 5, 7]
|
||||||
|
|
||||||
export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[], bountyCycle: number): void => {
|
export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[], bountyCycle: number): void => {
|
||||||
const table = String.fromCharCode(65 + (bountyCycle % 3));
|
const table = String.fromCharCode(65 + (bountyCycle % 3));
|
||||||
const vaultTable = String.fromCharCode(65 + ((bountyCycle + 1) % 3));
|
const vaultTable = String.fromCharCode(65 + ((bountyCycle + 1) % 3));
|
||||||
const deimosDTable = String.fromCharCode(65 + (bountyCycle % 2));
|
const deimosDTable = String.fromCharCode(65 + (bountyCycle % 2));
|
||||||
|
|
||||||
// TODO: xpAmounts need to be calculated based on the jobType somehow?
|
|
||||||
|
|
||||||
const seed = new SRng(bountyCycle).randomInt(0, 100_000);
|
const seed = new SRng(bountyCycle).randomInt(0, 100_000);
|
||||||
const bountyCycleStart = bountyCycle * 9000000;
|
const bountyCycleStart = bountyCycle * 9000000;
|
||||||
const bountyCycleEnd = bountyCycleStart + 9000000;
|
const bountyCycleEnd = bountyCycleStart + 9000000;
|
||||||
@ -481,7 +509,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 0,
|
masteryReq: 0,
|
||||||
minEnemyLevel: 5,
|
minEnemyLevel: 5,
|
||||||
maxEnemyLevel: 15,
|
maxEnemyLevel: 15,
|
||||||
xpAmounts: [430, 430, 430]
|
xpAmounts: generateXpAmounts(rng, 3, 1000, 1500)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(eidolonJobs),
|
jobType: rng.randomElement(eidolonJobs),
|
||||||
@ -489,7 +517,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 1,
|
masteryReq: 1,
|
||||||
minEnemyLevel: 10,
|
minEnemyLevel: 10,
|
||||||
maxEnemyLevel: 30,
|
maxEnemyLevel: 30,
|
||||||
xpAmounts: [620, 620, 620]
|
xpAmounts: generateXpAmounts(rng, 3, 1750, 2250)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(eidolonJobs),
|
jobType: rng.randomElement(eidolonJobs),
|
||||||
@ -497,7 +525,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 2,
|
masteryReq: 2,
|
||||||
minEnemyLevel: 20,
|
minEnemyLevel: 20,
|
||||||
maxEnemyLevel: 40,
|
maxEnemyLevel: 40,
|
||||||
xpAmounts: [670, 670, 670, 990]
|
xpAmounts: generateXpAmounts(rng, 4, 2500, 3000)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(eidolonJobs),
|
jobType: rng.randomElement(eidolonJobs),
|
||||||
@ -505,7 +533,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 3,
|
masteryReq: 3,
|
||||||
minEnemyLevel: 30,
|
minEnemyLevel: 30,
|
||||||
maxEnemyLevel: 50,
|
maxEnemyLevel: 50,
|
||||||
xpAmounts: [570, 570, 570, 570, 1110]
|
xpAmounts: generateXpAmounts(rng, 5, 3250, 3750)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(eidolonJobs),
|
jobType: rng.randomElement(eidolonJobs),
|
||||||
@ -513,7 +541,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 5,
|
masteryReq: 5,
|
||||||
minEnemyLevel: 40,
|
minEnemyLevel: 40,
|
||||||
maxEnemyLevel: 60,
|
maxEnemyLevel: 60,
|
||||||
xpAmounts: [740, 740, 740, 740, 1450]
|
xpAmounts: generateXpAmounts(rng, 5, 4000, 4500)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(eidolonJobs),
|
jobType: rng.randomElement(eidolonJobs),
|
||||||
@ -529,7 +557,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 0,
|
masteryReq: 0,
|
||||||
minEnemyLevel: 50,
|
minEnemyLevel: 50,
|
||||||
maxEnemyLevel: 70,
|
maxEnemyLevel: 70,
|
||||||
xpAmounts: [840, 840, 840, 840, 1650]
|
xpAmounts: generateXpAmounts(rng, 5, 4500, 5000)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -553,7 +581,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 0,
|
masteryReq: 0,
|
||||||
minEnemyLevel: 5,
|
minEnemyLevel: 5,
|
||||||
maxEnemyLevel: 15,
|
maxEnemyLevel: 15,
|
||||||
xpAmounts: [340, 340, 340]
|
xpAmounts: generateXpAmounts(rng, 3, 1000, 1500)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
@ -561,7 +589,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 1,
|
masteryReq: 1,
|
||||||
minEnemyLevel: 10,
|
minEnemyLevel: 10,
|
||||||
maxEnemyLevel: 30,
|
maxEnemyLevel: 30,
|
||||||
xpAmounts: [660, 660, 660]
|
xpAmounts: generateXpAmounts(rng, 3, 1750, 2250)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
@ -569,7 +597,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 2,
|
masteryReq: 2,
|
||||||
minEnemyLevel: 20,
|
minEnemyLevel: 20,
|
||||||
maxEnemyLevel: 40,
|
maxEnemyLevel: 40,
|
||||||
xpAmounts: [610, 610, 610, 900]
|
xpAmounts: generateXpAmounts(rng, 4, 2500, 3000)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
@ -577,7 +605,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 3,
|
masteryReq: 3,
|
||||||
minEnemyLevel: 30,
|
minEnemyLevel: 30,
|
||||||
maxEnemyLevel: 50,
|
maxEnemyLevel: 50,
|
||||||
xpAmounts: [600, 600, 600, 600, 1170]
|
xpAmounts: generateXpAmounts(rng, 5, 3250, 3750)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
@ -585,7 +613,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 5,
|
masteryReq: 5,
|
||||||
minEnemyLevel: 40,
|
minEnemyLevel: 40,
|
||||||
maxEnemyLevel: 60,
|
maxEnemyLevel: 60,
|
||||||
xpAmounts: [690, 690, 690, 690, 1350]
|
xpAmounts: generateXpAmounts(rng, 5, 4000, 4500)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(venusJobs),
|
jobType: rng.randomElement(venusJobs),
|
||||||
@ -601,7 +629,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 0,
|
masteryReq: 0,
|
||||||
minEnemyLevel: 50,
|
minEnemyLevel: 50,
|
||||||
maxEnemyLevel: 70,
|
maxEnemyLevel: 70,
|
||||||
xpAmounts: [780, 780, 780, 780, 1540]
|
xpAmounts: generateXpAmounts(rng, 5, 4500, 5000)
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
});
|
});
|
||||||
@ -625,7 +653,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 0,
|
masteryReq: 0,
|
||||||
minEnemyLevel: 5,
|
minEnemyLevel: 5,
|
||||||
maxEnemyLevel: 15,
|
maxEnemyLevel: 15,
|
||||||
xpAmounts: [5, 5, 5]
|
xpAmounts: generateXpAmounts(rng, 3, 12, 18)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(microplanetJobs),
|
jobType: rng.randomElement(microplanetJobs),
|
||||||
@ -633,7 +661,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 1,
|
masteryReq: 1,
|
||||||
minEnemyLevel: 15,
|
minEnemyLevel: 15,
|
||||||
maxEnemyLevel: 25,
|
maxEnemyLevel: 25,
|
||||||
xpAmounts: [12, 12, 12]
|
xpAmounts: generateXpAmounts(rng, 3, 24, 36)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(microplanetEndlessJobs),
|
jobType: rng.randomElement(microplanetEndlessJobs),
|
||||||
@ -650,7 +678,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 2,
|
masteryReq: 2,
|
||||||
minEnemyLevel: 30,
|
minEnemyLevel: 30,
|
||||||
maxEnemyLevel: 40,
|
maxEnemyLevel: 40,
|
||||||
xpAmounts: [17, 17, 17, 25]
|
xpAmounts: generateXpAmounts(rng, 4, 72, 88)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(microplanetJobs),
|
jobType: rng.randomElement(microplanetJobs),
|
||||||
@ -658,7 +686,7 @@ export const pushClassicBounties = (syndicateMissions: ISyndicateMissionInfo[],
|
|||||||
masteryReq: 3,
|
masteryReq: 3,
|
||||||
minEnemyLevel: 40,
|
minEnemyLevel: 40,
|
||||||
maxEnemyLevel: 60,
|
maxEnemyLevel: 60,
|
||||||
xpAmounts: [22, 22, 22, 22, 43]
|
xpAmounts: generateXpAmounts(rng, 5, 115, 135)
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
jobType: rng.randomElement(microplanetJobs),
|
jobType: rng.randomElement(microplanetJobs),
|
||||||
@ -938,8 +966,116 @@ 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;
|
||||||
|
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
|
||||||
|
const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000;
|
||||||
|
const eidolonCycleEnd = eidolonCycleStart + 9000;
|
||||||
|
const eidolonCycleNightStart = eidolonCycleEnd - 3000;
|
||||||
|
if (config.worldState.eidolonOverride == "day") {
|
||||||
|
if (
|
||||||
|
//timeSecs < eidolonCycleStart ||
|
||||||
|
isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleNightStart * 1000)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
timeSecs < eidolonCycleNightStart ||
|
||||||
|
isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleEnd * 1000)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (config.worldState?.vallisOverride) {
|
||||||
|
const vallisEpoch = 1541837628;
|
||||||
|
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
|
||||||
|
const vallisCycleStart = vallisEpoch + vallisCycle * 1600;
|
||||||
|
const vallisCycleEnd = vallisCycleStart + 1600;
|
||||||
|
const vallisCycleColdStart = vallisCycleStart + 400;
|
||||||
|
if (config.worldState.vallisOverride == "cold") {
|
||||||
|
if (
|
||||||
|
timeSecs < vallisCycleColdStart ||
|
||||||
|
isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleEnd * 1000)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (
|
||||||
|
//timeSecs < vallisCycleStart ||
|
||||||
|
isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleColdStart * 1000)
|
||||||
|
) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
};
|
||||||
|
|
||||||
export const getWorldState = (buildLabel?: string): IWorldState => {
|
export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||||
const timeSecs = config.worldState?.lockTime || Math.round(Date.now() / 1000);
|
let timeSecs = Math.round(Date.now() / 1000);
|
||||||
|
while (!doesTimeSatsifyConstraints(timeSecs)) {
|
||||||
|
timeSecs -= 60;
|
||||||
|
}
|
||||||
const timeMs = timeSecs * 1000;
|
const timeMs = timeSecs * 1000;
|
||||||
const day = Math.trunc((timeMs - EPOCH) / 86400000);
|
const day = Math.trunc((timeMs - EPOCH) / 86400000);
|
||||||
const week = Math.trunc(day / 7);
|
const week = Math.trunc(day / 7);
|
||||||
@ -954,6 +1090,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
Sorties: [],
|
Sorties: [],
|
||||||
LiteSorties: [],
|
LiteSorties: [],
|
||||||
GlobalUpgrades: [],
|
GlobalUpgrades: [],
|
||||||
|
VoidStorms: [],
|
||||||
EndlessXpChoices: [],
|
EndlessXpChoices: [],
|
||||||
KnownCalendarSeasons: [],
|
KnownCalendarSeasons: [],
|
||||||
...staticWorldState,
|
...staticWorldState,
|
||||||
@ -1150,12 +1287,27 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
worldState.KnownCalendarSeasons.push(getCalendarSeason(week + 1));
|
worldState.KnownCalendarSeasons.push(getCalendarSeason(week + 1));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Sentient Anomaly cycling every 30 minutes
|
// Void Storms
|
||||||
|
const hour = Math.trunc(timeMs / unixTimesInMs.hour);
|
||||||
|
const overLastHourStormExpiry = hour * unixTimesInMs.hour + 10 * unixTimesInMs.minute;
|
||||||
|
const thisHourStormActivation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute;
|
||||||
|
if (overLastHourStormExpiry > timeMs) {
|
||||||
|
pushVoidStorms(worldState.VoidStorms, hour - 2);
|
||||||
|
}
|
||||||
|
pushVoidStorms(worldState.VoidStorms, hour - 1);
|
||||||
|
if (isBeforeNextExpectedWorldStateRefresh(timeMs, thisHourStormActivation)) {
|
||||||
|
pushVoidStorms(worldState.VoidStorms, hour);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sentient Anomaly + Xtra Cheese cycles
|
||||||
const halfHour = Math.trunc(timeMs / (unixTimesInMs.hour / 2));
|
const halfHour = Math.trunc(timeMs / (unixTimesInMs.hour / 2));
|
||||||
const tmp = {
|
const hourInSeconds = 3600;
|
||||||
|
const cheeseInterval = hourInSeconds * 8;
|
||||||
|
const cheeseDuration = hourInSeconds * 2;
|
||||||
|
const cheeseIndex = Math.trunc(timeSecs / cheeseInterval);
|
||||||
|
const tmp: ITmp = {
|
||||||
cavabegin: "1690761600",
|
cavabegin: "1690761600",
|
||||||
PurchasePlatformLockEnabled: true,
|
PurchasePlatformLockEnabled: true,
|
||||||
tcsn: true,
|
|
||||||
pgr: {
|
pgr: {
|
||||||
ts: "1732572900",
|
ts: "1732572900",
|
||||||
en: "CUSTOM DECALS @ ZEVILA",
|
en: "CUSTOM DECALS @ ZEVILA",
|
||||||
@ -1176,8 +1328,16 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
},
|
},
|
||||||
ennnd: true,
|
ennnd: true,
|
||||||
mbrt: true,
|
mbrt: true,
|
||||||
|
fbst: {
|
||||||
|
a: cheeseIndex * cheeseInterval, // This has a bug where the client shows a negative time for "Xtra cheese starts in ..." until it refreshes the world state. This is because we're only providing the new activation as soon as that time/date is reached. However, this is 100% faithful to live.
|
||||||
|
e: cheeseIndex * cheeseInterval + cheeseDuration,
|
||||||
|
n: (cheeseIndex + 1) * cheeseInterval
|
||||||
|
},
|
||||||
sfn: [550, 553, 554, 555][halfHour % 4]
|
sfn: [550, 553, 554, 555][halfHour % 4]
|
||||||
};
|
};
|
||||||
|
if (Array.isArray(config.worldState?.circuitGameModes)) {
|
||||||
|
tmp.edg = config.worldState.circuitGameModes as TCircuitGameMode[];
|
||||||
|
}
|
||||||
worldState.Tmp = JSON.stringify(tmp);
|
worldState.Tmp = JSON.stringify(tmp);
|
||||||
|
|
||||||
return worldState;
|
return worldState;
|
||||||
@ -1275,8 +1435,14 @@ export const isArchwingMission = (node: IRegion): boolean => {
|
|||||||
|
|
||||||
export const getNightwaveSyndicateTag = (buildLabel: string | undefined): string | undefined => {
|
export const getNightwaveSyndicateTag = (buildLabel: string | undefined): string | undefined => {
|
||||||
if (config.worldState?.nightwaveOverride) {
|
if (config.worldState?.nightwaveOverride) {
|
||||||
|
if (config.worldState.nightwaveOverride in nightwaveTagToSeason) {
|
||||||
return config.worldState.nightwaveOverride;
|
return config.worldState.nightwaveOverride;
|
||||||
}
|
}
|
||||||
|
logger.warn(`ignoring invalid config value for worldState.nightwaveOverride`, {
|
||||||
|
value: config.worldState.nightwaveOverride,
|
||||||
|
valid_values: Object.keys(nightwaveTagToSeason)
|
||||||
|
});
|
||||||
|
}
|
||||||
if (!buildLabel || version_compare(buildLabel, "2025.05.20.10.18") >= 0) {
|
if (!buildLabel || version_compare(buildLabel, "2025.05.20.10.18") >= 0) {
|
||||||
return "RadioLegionIntermission13Syndicate";
|
return "RadioLegionIntermission13Syndicate";
|
||||||
}
|
}
|
||||||
|
@ -234,7 +234,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
HandlerPoints: number;
|
HandlerPoints: number;
|
||||||
MiscItems: IMiscItem[];
|
MiscItems: IMiscItem[];
|
||||||
HasOwnedVoidProjectionsPreviously?: boolean;
|
HasOwnedVoidProjectionsPreviously?: boolean;
|
||||||
ChallengesFixVersion: number;
|
ChallengesFixVersion?: number;
|
||||||
ChallengeProgress: IChallengeProgress[];
|
ChallengeProgress: IChallengeProgress[];
|
||||||
RawUpgrades: IRawUpgrade[];
|
RawUpgrades: IRawUpgrade[];
|
||||||
ReceivedStartingGear: boolean;
|
ReceivedStartingGear: boolean;
|
||||||
@ -641,11 +641,11 @@ export interface IFocusUpgrade {
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IFocusXP {
|
export interface IFocusXP {
|
||||||
AP_POWER: number;
|
AP_POWER?: number;
|
||||||
AP_TACTIC: number;
|
AP_TACTIC?: number;
|
||||||
AP_DEFENSE: number;
|
AP_DEFENSE?: number;
|
||||||
AP_ATTACK: number;
|
AP_ATTACK?: number;
|
||||||
AP_WARD: number;
|
AP_WARD?: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export type TFocusPolarity = keyof IFocusXP;
|
export type TFocusPolarity = keyof IFocusXP;
|
||||||
|
@ -12,6 +12,7 @@ export interface IWorldState {
|
|||||||
GlobalUpgrades: IGlobalUpgrade[];
|
GlobalUpgrades: IGlobalUpgrade[];
|
||||||
ActiveMissions: IFissure[];
|
ActiveMissions: IFissure[];
|
||||||
NodeOverrides: INodeOverride[];
|
NodeOverrides: INodeOverride[];
|
||||||
|
VoidStorms: IVoidStorm[];
|
||||||
PVPChallengeInstances: IPVPChallengeInstance[];
|
PVPChallengeInstances: IPVPChallengeInstance[];
|
||||||
EndlessXpChoices: IEndlessXpChoice[];
|
EndlessXpChoices: IEndlessXpChoice[];
|
||||||
SeasonInfo?: {
|
SeasonInfo?: {
|
||||||
@ -131,6 +132,14 @@ export interface ILiteSortie {
|
|||||||
}[];
|
}[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IVoidStorm {
|
||||||
|
_id: IOid;
|
||||||
|
Node: string;
|
||||||
|
Activation: IMongoDate;
|
||||||
|
Expiry: IMongoDate;
|
||||||
|
ActiveMissionTier: string;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IPVPChallengeInstance {
|
export interface IPVPChallengeInstance {
|
||||||
_id: IOid;
|
_id: IOid;
|
||||||
challengeTypeRefID: string;
|
challengeTypeRefID: string;
|
||||||
@ -182,3 +191,48 @@ export interface ICalendarEvent {
|
|||||||
dialogueName?: string;
|
dialogueName?: string;
|
||||||
dialogueConvo?: string;
|
dialogueConvo?: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export type TCircuitGameMode =
|
||||||
|
| "Survival"
|
||||||
|
| "VoidFlood"
|
||||||
|
| "Excavation"
|
||||||
|
| "Defense"
|
||||||
|
| "Exterminate"
|
||||||
|
| "Assassination"
|
||||||
|
| "Alchemy";
|
||||||
|
|
||||||
|
export interface ITmp {
|
||||||
|
cavabegin: string;
|
||||||
|
PurchasePlatformLockEnabled: boolean; // Seems unused
|
||||||
|
pgr: IPgr;
|
||||||
|
ennnd?: boolean; // True if 1999 demo is available (no effect for >=38.6.0)
|
||||||
|
mbrt?: boolean; // Related to mobile app rating request
|
||||||
|
fbst: IFbst;
|
||||||
|
sfn: number;
|
||||||
|
edg?: TCircuitGameMode[]; // The Circuit game modes overwrite
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IPgr {
|
||||||
|
ts: string;
|
||||||
|
en: string;
|
||||||
|
fr: string;
|
||||||
|
it: string;
|
||||||
|
de: string;
|
||||||
|
es: string;
|
||||||
|
pt: string;
|
||||||
|
ru: string;
|
||||||
|
pl: string;
|
||||||
|
uk: string;
|
||||||
|
tr: string;
|
||||||
|
ja: string;
|
||||||
|
zh: string;
|
||||||
|
ko: string;
|
||||||
|
tc: string;
|
||||||
|
th: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
interface IFbst {
|
||||||
|
a: number;
|
||||||
|
e: number;
|
||||||
|
n: number;
|
||||||
|
}
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "5f456e00c96976e97d6b7fd7"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/ProspectorVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Deimos/DeimosUncommonGemACutItem",
|
|
||||||
"PremiumPrice": [13, 13],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 10,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e93a8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Deimos/DeimosCommonGemBCutItem",
|
|
||||||
"PremiumPrice": [7, 7],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e93a9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Deimos/DeimosCommonGemACutItem",
|
|
||||||
"PremiumPrice": [7, 7],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e93aa"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "2BBC116116C757F6AF4FBC3B9BF754C8",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "5dbb4c41e966f7886c3ce939"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/HarrowQuestKeyOrnament",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 25,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/PrimeBucks",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e945f"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 10,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9468"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/StoreItems/CreditBundles/150000Credits",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 5,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9469"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 10,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 35000,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e946a"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 10,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e946b"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "62B64A8065B7C0FA345895D4BC234621",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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,62 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "59dfe591314805ffe1d47c0a"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Ostron/ProspectorVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Eidolon/RareGemACutAItem",
|
|
||||||
"PremiumPrice": [19, 19],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 5,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e98f0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Eidolon/CommonGemBCutAItem",
|
|
||||||
"PremiumPrice": [8, 8],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e98f1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Eidolon/CommonGemACutAItem",
|
|
||||||
"PremiumPrice": [5, 5],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e98f2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"MaxDailyPurchases": 0,
|
|
||||||
"PropertyTextHash": "773C6968D9A65506CD28DF28C768F0DA",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "5be4a159b144f3cdf1c22ebb"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Solaris/ProspectorVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Solaris/SolarisRareGemACutItem",
|
|
||||||
"PremiumPrice": [20, 20],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 5,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9777"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Solaris/SolarisCommonGemBCutItem",
|
|
||||||
"PremiumPrice": [10, 10],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9778"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Solaris/SolarisCommonGemACutItem",
|
|
||||||
"PremiumPrice": [8, 8],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9779"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "A5756A21991FF49CFA7D096B4026515B",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -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,83 +0,0 @@
|
|||||||
{
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeEquilibrium": "+20% Energy from Health pickups, +20% Health from Energy pickups",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeEquilibriumMythic": "+30% Energy from Health pickups, +30% Health from Energy pickups",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeMeleeCritDamage": "+25% Melee Critical Damage",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeMeleeCritDamageMythic": "+37.5% Melee Critical Damage",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradePrimaryStatusChance": "+25% Primary Status Chance",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradePrimaryStatusChanceMythic": "+37.5% Primary Status Chance",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeSecondaryCritChance": "+25% Secondary Critical Chance",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeSecondaryCritChanceMythic": "+37.5% Secondary Critical Chance",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeAbilityDuration": "+10% Ability Duration",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeAbilityDurationMythic": "+15% Ability Duration",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeAbilityStrength": "+10% Ability Strength",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeAbilityStrengthMythic": "+15% Ability Strength",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeArmourMax": "+150 Armor",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeArmourMaxMythic": "+225 Armor",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeBlastProc": "+5 Shields on inflicting Blast Status",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeBlastProcMythic": "+7.5 Shields on inflicting Blast Status",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCastingSpeed": "+25% Casting Speed",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCastingSpeedMythic": "+37.5% Casting Speed",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCorrosiveDamageBoost": "+10% Ability Damage on enemies affected by Corrosion Status",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCorrosiveDamageBoostMythic": "+15% Ability Damage on enemies affected by Corrosion Status",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCorrosiveStack": "Increase max stacks of Corrosion Status by +2",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCorrosiveStackMythic": "Increase max stacks of Corrosion Status by +3",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCritDamageBoost": "+25% Melee Critical Damage (Doubles over 500 Energy)",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCritDamageBoostMythic": "+37% Melee Critical Damage (Doubles over 500 Energy)",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeElectricDamage": "+30% Primary Electricity Damage (+10% per additional Shard)",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeElectricDamageMythic": "+45% Primary Electricity Damage (+15% per additional Shard)",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeElectricDamageBoost": "+10% Ability Damage on enemies affected by Electricity Status",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeElectricDamageBoostMythic": "+15% Ability Damage on enemies affected by Electricity Status",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeEnergyMax": "+50 Energy Max",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeEnergyMaxMythic": "+75 Energy Max",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeGlobeEffectEnergy": "+50% Energy Orb Effectiveness",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeGlobeEffectEnergyMythic": "+75% Energy Orb Effectiveness",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeGlobeEffectHealth": "+100% Health Orb Effectiveness",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeGlobeEffectHealthMythic": "+150% Health Orb Effectiveness",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeHealthMax": "+150 Health",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeHealthMaxMythic": "+225 Health",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeHPBoostFromImpact": "+1 Health per enemy killed with Blast Damage (Max 300 Health)",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeHPBoostFromImpactMythic": "+2 Health per enemy killed with Blast Damage (Max 450 Health)",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeParkourVelocity": "+15% Parkour Velocity",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeParkourVelocityMythic": "+22.5% Parkour Velocity",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeRadiationDamageBoost": "+10% Ability Damage on enemies affected by Radiation Status",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeRadiationDamageBoostMythic": "+15% Ability Damage on enemies affected by Radiation Status",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeRegen": "+5 Health Regen/s",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeRegenMythic": "+7.5 Health Regen/s",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeShieldMax": "+150 Shield",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeShieldMaxMythic": "+225 Shield",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeStartingEnergy": "+30% Energy on Spawn",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeStartingEnergyMythic": "+45% Energy on Spawn",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeToxinDamage": "+30% Toxin Status Effect Damage",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeToxinDamageMythic": "+45% Toxin Status Effect Damage",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeToxinHeal": "+2 Health on damaging enemies with Toxin Status",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeToxinHealMythic": "+3 Health on damaging enemies with Toxin Status",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWeaponCritBoostFromHeat": "+1% Secondary Critical Chance per Heat-affected enemy killed (Max 50%)",
|
|
||||||
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWeaponCritBoostFromHeatMythic": "+1.5% Secondary Critical Chance per Heat-affected enemy killed (Max 75%)",
|
|
||||||
|
|
||||||
"/Lotus/Upgrades/Mods/Warframe/AvatarAbilityRangeMod": "+7.5% Ability Range",
|
|
||||||
"/Lotus/Upgrades/Mods/Warframe/AvatarAbilityEfficiencyMod": "+5% Ability Efficiency",
|
|
||||||
"/Lotus/Upgrades/Mods/Warframe/AvatarEnergyRegenMod": "+0.5 Energy Regen/s",
|
|
||||||
"/Lotus/Upgrades/Mods/Warframe/AvatarEnemyRadarMod": "+5m Enemy Radar",
|
|
||||||
"/Lotus/Upgrades/Mods/Warframe/AvatarLootRadarMod": "+7m Loot Radar",
|
|
||||||
|
|
||||||
"/Lotus/Upgrades/Mods/Rifle/WeaponAmmoMaxMod": "+15% Ammo Max",
|
|
||||||
|
|
||||||
"/Lotus/Upgrades/Mods/Aura/EnemyArmorReductionAuraMod": "-3% Enemy Armor",
|
|
||||||
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionAmmoMod": "100% Primary and Secondary Magazine Refill on Mercy",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionHealthDropMod": "100% chance to drop a Health Orb on Mercy",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionEnergyDropMod": "50% chance to drop an Energy Orb on Mercy",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Cipher/OnFailHackResetMod": "+50% to retry on Hacking failure",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Cipher/DamageReductionOnHackMod": "75% Damage Reduction while Hacking",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionReviveCompanionMod": "Mercy Kills reduce Companion Recovery by 15s",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionParkourSpeedMod": "+60% Parkour Speed after a Mercy for 15s",
|
|
||||||
"/Lotus/Upgrades/Mods/Warframe/AvatarTimeLimitIncreaseMod": "+8s to Hacking",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Cipher/ElectrifyOnHackMod": "Shock enemies within 20m while Hacking",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionTerrifyMod": "50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Cipher/OnHackLockersMod": "Unlock 5 lockers within 20m after Hacking",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionBlindMod": "Blind enemies within 18m on Mercy",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionDrainPowerMod": "100% chance for next ability cast to gain +50% Ability Strength on Mercy",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Cipher/OnHackSprintSpeedMod": "+75% Sprint Speed for 15s after Hacking",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Assassin/SwiftExecuteMod": "Speed of Mercy Kills increased by 50%",
|
|
||||||
"/Lotus/Upgrades/Mods/DataSpike/Cipher/OnHackInvisMod": "Invisible for 15 seconds after hacking"
|
|
||||||
}
|
|
@ -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" },
|
"PrimeAccessAvailability": { "State": "PRIME1" },
|
||||||
"PrimeVaultAvailabilities": [false, false, false, false, false],
|
"PrimeVaultAvailabilities": [false, false, false, false, false],
|
||||||
"PrimeTokenAvailability": true,
|
"PrimeTokenAvailability": true,
|
||||||
|
@ -1,10 +1,6 @@
|
|||||||
<!doctype html>
|
<!doctype html>
|
||||||
<html lang="en">
|
<html lang="en" data-bs-theme="dark">
|
||||||
<head>
|
<head>
|
||||||
<script>
|
|
||||||
// Set theme early to prevent flash of incorrect style
|
|
||||||
document.documentElement.setAttribute("data-bs-theme", localStorage.getItem("theme") || "dark");
|
|
||||||
</script>
|
|
||||||
<title>OpenWF WebUI</title>
|
<title>OpenWF WebUI</title>
|
||||||
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
<meta name="viewport" content="width=device-width, initial-scale=1" />
|
||||||
<link rel="stylesheet" href="/webui/libs/bootstrap.min.css" />
|
<link rel="stylesheet" href="/webui/libs/bootstrap.min.css" />
|
||||||
@ -37,13 +33,6 @@
|
|||||||
<li><a class="dropdown-item" href="#" data-lang="tc" onclick="event.preventDefault();setLanguage('tc');">繁體中文</a></li>
|
<li><a class="dropdown-item" href="#" data-lang="tc" onclick="event.preventDefault();setLanguage('tc');">繁體中文</a></li>
|
||||||
<li><a class="dropdown-item" href="#" data-lang="th" onclick="event.preventDefault();setLanguage('th');">แบบไทย</a></li>
|
<li><a class="dropdown-item" href="#" data-lang="th" onclick="event.preventDefault();setLanguage('th');">แบบไทย</a></li>
|
||||||
</ul>
|
</ul>
|
||||||
</li>
|
|
||||||
<li class="nav-item dropdown">
|
|
||||||
<button id="active-theme-name" class="nav-link dropdown-toggle" data-bs-toggle="dropdown" aria-expanded="false"></button>
|
|
||||||
<ul class="dropdown-menu dropdown-menu-end">
|
|
||||||
<li><a class="dropdown-item active" href="#" data-theme="dark" onclick="event.preventDefault();setTheme('dark');" data-loc="navbar_darkTheme"></a></li>
|
|
||||||
<li><a class="dropdown-item" href="#" data-theme="light" onclick="event.preventDefault();setTheme('light');" data-loc="navbar_lightTheme"></a></li>
|
|
||||||
</ul>
|
|
||||||
</li>
|
</li>
|
||||||
<li class="nav-item dropdown user-dropdown">
|
<li class="nav-item dropdown user-dropdown">
|
||||||
<button class="nav-link dropdown-toggle displayname" data-bs-toggle="dropdown" aria-expanded="false"></button>
|
<button class="nav-link dropdown-toggle displayname" data-bs-toggle="dropdown" aria-expanded="false"></button>
|
||||||
@ -427,6 +416,20 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="col-lg-6">
|
||||||
|
<div class="card mb-3" style="height: 400px;">
|
||||||
|
<h5 class="card-header" data-loc="inventory_Boosters"></h5>
|
||||||
|
<div class="card-body overflow-auto">
|
||||||
|
<form class="input-group mb-3" onsubmit="doAcquireBoosters();return false;">
|
||||||
|
<input class="form-control" id="acquire-type-Boosters" list="datalist-Boosters" />
|
||||||
|
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||||
|
</form>
|
||||||
|
<table class="table table-hover w-100">
|
||||||
|
<tbody id="Boosters-list"></tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div class="card mb-3">
|
<div class="card mb-3">
|
||||||
<h5 class="card-header" data-loc="general_bulkActions"></h5>
|
<h5 class="card-header" data-loc="general_bulkActions"></h5>
|
||||||
@ -568,7 +571,7 @@
|
|||||||
<div id="server-settings-no-perms" class="d-none">
|
<div id="server-settings-no-perms" class="d-none">
|
||||||
<p class="card-text" data-loc="cheats_administratorRequirement"></p>
|
<p class="card-text" data-loc="cheats_administratorRequirement"></p>
|
||||||
</div>
|
</div>
|
||||||
<form id="server-settings" class="d-none" onsubmit="doChangeSettings();return false;">
|
<div id="server-settings" class="d-none">
|
||||||
<div class="form-check">
|
<div class="form-check">
|
||||||
<input class="form-check-input" type="checkbox" id="skipTutorial" />
|
<input class="form-check-input" type="checkbox" id="skipTutorial" />
|
||||||
<label class="form-check-label" for="skipTutorial" data-loc="cheats_skipTutorial"></label>
|
<label class="form-check-label" for="skipTutorial" data-loc="cheats_skipTutorial"></label>
|
||||||
@ -729,12 +732,21 @@
|
|||||||
<input class="form-check-input" type="checkbox" id="fastClanAscension" />
|
<input class="form-check-input" type="checkbox" id="fastClanAscension" />
|
||||||
<label class="form-check-label" for="fastClanAscension" data-loc="cheats_fastClanAscension"></label>
|
<label class="form-check-label" for="fastClanAscension" data-loc="cheats_fastClanAscension"></label>
|
||||||
</div>
|
</div>
|
||||||
<div class="form-group mt-2">
|
<form class="form-group mt-2" onsubmit="doSaveConfig('spoofMasteryRank'); return false;">
|
||||||
<label class="form-label" for="spoofMasteryRank" data-loc="cheats_spoofMasteryRank"></label>
|
<label class="form-label" for="spoofMasteryRank" data-loc="cheats_spoofMasteryRank"></label>
|
||||||
|
<div class="input-group">
|
||||||
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" max="65535" />
|
<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>
|
</div>
|
||||||
<button class="btn btn-primary mt-3" type="submit" data-loc="cheats_saveSettings"></button>
|
|
||||||
</form>
|
</form>
|
||||||
|
<form class="form-group mt-2" onsubmit="doSaveConfig('nightwaveStandingMultiplier'); return false;">
|
||||||
|
<label class="form-label" for="nightwaveStandingMultiplier" data-loc="cheats_nightwaveStandingMultiplier"></label>
|
||||||
|
<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>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
@ -815,6 +827,7 @@
|
|||||||
<datalist id="datalist-ModularParts-CATBROW_MUTAGEN"></datalist>
|
<datalist id="datalist-ModularParts-CATBROW_MUTAGEN"></datalist>
|
||||||
<datalist id="datalist-ModularParts-KUBROW_ANTIGEN"></datalist>
|
<datalist id="datalist-ModularParts-KUBROW_ANTIGEN"></datalist>
|
||||||
<datalist id="datalist-ModularParts-KUBROW_MUTAGEN"></datalist>
|
<datalist id="datalist-ModularParts-KUBROW_MUTAGEN"></datalist>
|
||||||
|
<datalist id="datalist-Boosters"></datalist>
|
||||||
<script src="/webui/libs/jquery-3.6.0.min.js"></script>
|
<script src="/webui/libs/jquery-3.6.0.min.js"></script>
|
||||||
<script src="/webui/libs/whirlpool-js.min.js"></script>
|
<script src="/webui/libs/whirlpool-js.min.js"></script>
|
||||||
<script src="/webui/libs/single.js"></script>
|
<script src="/webui/libs/single.js"></script>
|
||||||
|
@ -29,7 +29,7 @@ function loginFromLocalStorage() {
|
|||||||
},
|
},
|
||||||
() => {
|
() => {
|
||||||
logout();
|
logout();
|
||||||
alert(isRegister ? "Registration failed. Account already exists?" : "Login failed");
|
alert(loc(isRegister ? "code_regFail" : "code_loginFail"));
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
@ -155,7 +155,6 @@ function setActiveLanguage(lang) {
|
|||||||
script.src = "/translations/" + webui_lang + ".js";
|
script.src = "/translations/" + webui_lang + ".js";
|
||||||
script.onload = function () {
|
script.onload = function () {
|
||||||
updateLocElements();
|
updateLocElements();
|
||||||
setTheme(localStorage.getItem("theme") ?? "dark");
|
|
||||||
resolve(window.dict);
|
resolve(window.dict);
|
||||||
};
|
};
|
||||||
document.documentElement.appendChild(script);
|
document.documentElement.appendChild(script);
|
||||||
@ -173,15 +172,6 @@ function setLanguage(lang) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
function setTheme(theme) {
|
|
||||||
localStorage.setItem("theme", theme);
|
|
||||||
document.documentElement.setAttribute("data-bs-theme", theme);
|
|
||||||
const themeName = document.querySelector(`[data-theme="${theme}"]`)?.textContent;
|
|
||||||
document.getElementById("active-theme-name").textContent = themeName;
|
|
||||||
document.querySelectorAll("[data-theme].active").forEach(el => el.classList.remove("active"));
|
|
||||||
document.querySelector(`[data-theme="${theme}"]`)?.classList.add("active");
|
|
||||||
}
|
|
||||||
|
|
||||||
const webUiModularWeapons = [
|
const webUiModularWeapons = [
|
||||||
"/Lotus/Weapons/Sentients/OperatorAmplifiers/OperatorAmpWeapon",
|
"/Lotus/Weapons/Sentients/OperatorAmplifiers/OperatorAmpWeapon",
|
||||||
"/Lotus/Weapons/Ostron/Melee/LotusModularWeapon",
|
"/Lotus/Weapons/Ostron/Melee/LotusModularWeapon",
|
||||||
@ -223,6 +213,86 @@ function fetchItemList() {
|
|||||||
document.getElementById("changeSyndicate").innerHTML = "";
|
document.getElementById("changeSyndicate").innerHTML = "";
|
||||||
document.getElementById("changeSyndicate").appendChild(syndicateNone);
|
document.getElementById("changeSyndicate").appendChild(syndicateNone);
|
||||||
|
|
||||||
|
// prettier-ignore
|
||||||
|
data.archonCrystalUpgrades = {
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeEquilibrium": loc("upgrade_Equilibrium").split("|VAL|").join("20"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeEquilibriumMythic": loc("upgrade_Equilibrium").split("|VAL|").join("30"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeMeleeCritDamage": loc("upgrade_MeleeCritDamage").split("|VAL|").join("25"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeMeleeCritDamageMythic": loc("upgrade_MeleeCritDamage").split("|VAL|").join("37.5"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradePrimaryStatusChance": loc("upgrade_PrimaryStatusChance").split("|VAL|").join("25"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradePrimaryStatusChanceMythic": loc("upgrade_PrimaryStatusChance").split("|VAL|").join("37.5"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeSecondaryCritChance": loc("upgrade_SecondaryCritChance").split("|VAL|").join("25"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeSecondaryCritChanceMythic": loc("upgrade_SecondaryCritChance").split("|VAL|").join("37.5"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeAbilityDuration": loc("upgrade_WarframeAbilityDuration").split("|VAL|").join("10"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeAbilityDurationMythic": loc("upgrade_WarframeAbilityDuration").split("|VAL|").join("15"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeAbilityStrength": loc("upgrade_WarframeAbilityStrength").split("|VAL|").join("10"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeAbilityStrengthMythic": loc("upgrade_WarframeAbilityStrength").split("|VAL|").join("15"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeArmourMax": loc("upgrade_WarframeArmourMax").split("|VAL|").join("150"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeArmourMaxMythic": loc("upgrade_WarframeArmourMax").split("|VAL|").join("225"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeBlastProc": loc("upgrade_WarframeBlastProc").split("|VAL|").join("5"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeBlastProcMythic": loc("upgrade_WarframeBlastProc").split("|VAL|").join("7.5"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCastingSpeed": loc("upgrade_WarframeCastingSpeed").split("|VAL|").join("25"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCastingSpeedMythic": loc("upgrade_WarframeCastingSpeed").split("|VAL|").join("37.5"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCorrosiveDamageBoost": loc("upgrade_WarframeCorrosiveDamageBoost").split("|VAL|").join("10"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCorrosiveDamageBoostMythic": loc("upgrade_WarframeCorrosiveDamageBoost").split("|VAL|").join("15"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCorrosiveStack": loc("upgrade_WarframeCorrosiveStack").split("|VAL|").join("2"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCorrosiveStackMythic": loc("upgrade_WarframeCorrosiveStack").split("|VAL|").join("3"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCritDamageBoost": loc("upgrade_WarframeCritDamageBoost").split("|VAL|").join("25"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeCritDamageBoostMythic": loc("upgrade_WarframeCritDamageBoost").split("|VAL|").join("37"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeElectricDamage": loc("upgrade_WarframeElectricDamage").split("|VAL1|").join("30").split("|VAL2|").join("10"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeElectricDamageMythic": loc("upgrade_WarframeElectricDamage").split("|VAL1|").join("45").split("|VAL2|").join("15"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeElectricDamageBoost": loc("upgrade_WarframeElectricDamageBoost").split("|VAL|").join("10"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeElectricDamageBoostMythic": loc("upgrade_WarframeElectricDamageBoost").split("|VAL|").join("15"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeEnergyMax": loc("upgrade_WarframeEnergyMax").split("|VAL|").join("50"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeEnergyMaxMythic": loc("upgrade_WarframeEnergyMax").split("|VAL|").join("75"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeGlobeEffectEnergy": loc("upgrade_WarframeGlobeEffectEnergy").split("|VAL|").join("50"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeGlobeEffectEnergyMythic": loc("upgrade_WarframeGlobeEffectEnergy").split("|VAL|").join("75"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeGlobeEffectHealth": loc("upgrade_WarframeGlobeEffectHealth").split("|VAL|").join("100"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeGlobeEffectHealthMythic": loc("upgrade_WarframeGlobeEffectHealth").split("|VAL|").join("150"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeHealthMax": loc("upgrade_WarframeHealthMax").split("|VAL|").join("150"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeHealthMaxMythic": loc("upgrade_WarframeHealthMax").split("|VAL|").join("225"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeHPBoostFromImpact": loc("upgrade_WarframeHPBoostFromImpact").split("|VAL1|").join("1").split("|VAL2|").join("300"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeHPBoostFromImpactMythic": loc("upgrade_WarframeHPBoostFromImpact").split("|VAL1|").join("2").split("|VAL2|").join("450"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeParkourVelocity": loc("upgrade_WarframeParkourVelocity").split("|VAL|").join("15"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeParkourVelocityMythic": loc("upgrade_WarframeParkourVelocity").split("|VAL|").join("22.5"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeRadiationDamageBoost": loc("upgrade_WarframeRadiationDamageBoost").split("|VAL|").join("10"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeRadiationDamageBoostMythic": loc("upgrade_WarframeRadiationDamageBoost").split("|VAL|").join("15"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeRegen": loc("upgrade_WarframeRegen").split("|VAL|").join("5"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeRegenMythic": loc("upgrade_WarframeRegen").split("|VAL|").join("7.5"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeShieldMax": loc("upgrade_WarframeShieldMax").split("|VAL|").join("150"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeShieldMaxMythic": loc("upgrade_WarframeShieldMax").split("|VAL|").join("225"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeStartingEnergy": loc("upgrade_WarframeStartingEnergy").split("|VAL|").join("30"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeStartingEnergyMythic": loc("upgrade_WarframeStartingEnergy").split("|VAL|").join("45"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeToxinDamage": loc("upgrade_WarframeToxinDamage").split("|VAL|").join("30"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeToxinDamageMythic": loc("upgrade_WarframeToxinDamage").split("|VAL|").join("45"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeToxinHeal": loc("upgrade_WarframeToxinHeal").split("|VAL|").join("2"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWarframeToxinHealMythic": loc("upgrade_WarframeToxinHeal").split("|VAL|").join("3"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWeaponCritBoostFromHeat": loc("upgrade_WeaponCritBoostFromHeat").split("|VAL1|").join("1").split("|VAL2|").join("50"),
|
||||||
|
"/Lotus/Upgrades/Invigorations/ArchonCrystalUpgrades/ArchonCrystalUpgradeWeaponCritBoostFromHeatMythic": loc("upgrade_WeaponCritBoostFromHeat").split("|VAL1|").join("1.5").split("|VAL2|").join("75"),
|
||||||
|
"/Lotus/Upgrades/Mods/Warframe/AvatarAbilityRangeMod": loc("upgrade_AvatarAbilityRange"),
|
||||||
|
"/Lotus/Upgrades/Mods/Warframe/AvatarAbilityEfficiencyMod": loc("upgrade_AvatarAbilityEfficiency"),
|
||||||
|
"/Lotus/Upgrades/Mods/Warframe/AvatarEnergyRegenMod": loc("upgrade_AvatarEnergyRegen"),
|
||||||
|
"/Lotus/Upgrades/Mods/Warframe/AvatarEnemyRadarMod": loc("upgrade_AvatarEnemyRadar"),
|
||||||
|
"/Lotus/Upgrades/Mods/Warframe/AvatarLootRadarMod": loc("upgrade_AvatarLootRadar"),
|
||||||
|
"/Lotus/Upgrades/Mods/Rifle/WeaponAmmoMaxMod": loc("upgrade_WeaponAmmoMax"),
|
||||||
|
"/Lotus/Upgrades/Mods/Aura/EnemyArmorReductionAuraMod": loc("upgrade_EnemyArmorReductionAura"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionAmmoMod": loc("upgrade_OnExecutionAmmo"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionHealthDropMod": loc("upgrade_OnExecutionHealthDrop"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionEnergyDropMod": loc("upgrade_OnExecutionEnergyDrop"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Cipher/OnFailHackResetMod": loc("upgrade_OnFailHackReset"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Cipher/DamageReductionOnHackMod": loc("upgrade_DamageReductionOnHack"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionReviveCompanionMod": loc("upgrade_OnExecutionReviveCompanion"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionParkourSpeedMod": loc("upgrade_OnExecutionParkourSpeed"),
|
||||||
|
"/Lotus/Upgrades/Mods/Warframe/AvatarTimeLimitIncreaseMod": loc("upgrade_AvatarTimeLimitIncrease"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Cipher/ElectrifyOnHackMod": loc("upgrade_ElectrifyOnHack"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionTerrifyMod": loc("upgrade_OnExecutionTerrify"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Cipher/OnHackLockersMod": loc("upgrade_OnHackLockers"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionBlindMod": loc("upgrade_OnExecutionBlind"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Assassin/OnExecutionDrainPowerMod": loc("upgrade_OnExecutionDrainPower"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Cipher/OnHackSprintSpeedMod": loc("upgrade_OnHackSprintSpeed"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Assassin/SwiftExecuteMod": loc("upgrade_SwiftExecute"),
|
||||||
|
"/Lotus/Upgrades/Mods/DataSpike/Cipher/OnHackInvisMod": loc("upgrade_OnHackInvis"),
|
||||||
|
};
|
||||||
window.archonCrystalUpgrades = data.archonCrystalUpgrades;
|
window.archonCrystalUpgrades = data.archonCrystalUpgrades;
|
||||||
|
|
||||||
// Add mods mising in data sources
|
// Add mods mising in data sources
|
||||||
@ -1021,6 +1091,63 @@ function updateInventory() {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
document.getElementById("changeSyndicate").value = data.SupportedSyndicate ?? "";
|
document.getElementById("changeSyndicate").value = data.SupportedSyndicate ?? "";
|
||||||
|
|
||||||
|
document.getElementById("Boosters-list").innerHTML = "";
|
||||||
|
const now = Math.floor(Date.now() / 1000);
|
||||||
|
data.Boosters.forEach(({ ItemType, ExpiryDate }) => {
|
||||||
|
if (ExpiryDate < now) {
|
||||||
|
// Booster has expired, skip it
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const tr = document.createElement("tr");
|
||||||
|
{
|
||||||
|
const td = document.createElement("td");
|
||||||
|
td.textContent = itemMap[ItemType]?.name ?? ItemType;
|
||||||
|
tr.appendChild(td);
|
||||||
|
}
|
||||||
|
{
|
||||||
|
const td = document.createElement("td");
|
||||||
|
td.classList = "text-end text-nowrap";
|
||||||
|
const timeString = formatDatetime("%Y-%m-%d %H:%M:%s", ExpiryDate * 1000);
|
||||||
|
const inlineForm = document.createElement("form");
|
||||||
|
const input = document.createElement("input");
|
||||||
|
|
||||||
|
inlineForm.style.display = "inline-block";
|
||||||
|
inlineForm.onsubmit = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
doChangeBoosterExpiry(ItemType, input);
|
||||||
|
};
|
||||||
|
input.type = "datetime-local";
|
||||||
|
input.classList.add("form-control");
|
||||||
|
input.classList.add("form-control-sm");
|
||||||
|
input.value = timeString;
|
||||||
|
let changed = false;
|
||||||
|
input.onchange = function () {
|
||||||
|
changed = true;
|
||||||
|
};
|
||||||
|
input.onblur = function () {
|
||||||
|
if (changed) {
|
||||||
|
doChangeBoosterExpiry(ItemType, input);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
inlineForm.appendChild(input);
|
||||||
|
|
||||||
|
td.appendChild(inlineForm);
|
||||||
|
|
||||||
|
const removeButton = document.createElement("a");
|
||||||
|
removeButton.title = loc("code_remove");
|
||||||
|
removeButton.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 448 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M135.2 17.7L128 32H32C14.3 32 0 46.3 0 64S14.3 96 32 96H416c17.7 0 32-14.3 32-32s-14.3-32-32-32H320l-7.2-14.3C307.4 6.8 296.3 0 284.2 0H163.8c-12.1 0-23.2 6.8-28.6 17.7zM416 128H32L53.2 467c1.6 25.3 22.6 45 47.9 45H346.9c25.3 0 46.3-19.7 47.9-45L416 128z"/></svg>`;
|
||||||
|
removeButton.href = "#";
|
||||||
|
removeButton.onclick = function (event) {
|
||||||
|
event.preventDefault();
|
||||||
|
setBooster(ItemType, 0);
|
||||||
|
};
|
||||||
|
td.appendChild(removeButton);
|
||||||
|
|
||||||
|
tr.appendChild(td);
|
||||||
|
}
|
||||||
|
document.getElementById("Boosters-list").appendChild(tr);
|
||||||
|
});
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1634,34 +1761,29 @@ function doAcquireMod() {
|
|||||||
|
|
||||||
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
|
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
|
||||||
|
|
||||||
function doChangeSettings() {
|
for (const id of uiConfigs) {
|
||||||
revalidateAuthz(() => {
|
const elm = document.getElementById(id);
|
||||||
fetch("/custom/config?" + window.authz)
|
if (elm.type == "checkbox") {
|
||||||
.then(response => response.json())
|
elm.onchange = function () {
|
||||||
.then(json => {
|
|
||||||
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({
|
$.post({
|
||||||
url: "/custom/config?" + window.authz,
|
url: "/custom/config?" + window.authz,
|
||||||
contentType: "text/plain",
|
contentType: "application/json",
|
||||||
data: JSON.stringify(json, null, 2)
|
data: JSON.stringify({ key: id, value: this.checked })
|
||||||
}).then(() => {
|
}).then(() => {
|
||||||
// A few cheats affect the inventory response which in turn may change what values we need to show
|
if (["infiniteCredits", "infinitePlatinum", "infiniteEndo", "infiniteRegalAya"].indexOf(id) != -1) {
|
||||||
updateInventory();
|
updateInventory();
|
||||||
|
}
|
||||||
});
|
});
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function doSaveConfig(id) {
|
||||||
|
const elm = document.getElementById(id);
|
||||||
|
$.post({
|
||||||
|
url: "/custom/config?" + window.authz,
|
||||||
|
contentType: "application/json",
|
||||||
|
data: JSON.stringify({ key: id, value: parseInt(elm.value) })
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -2037,3 +2159,77 @@ function handleModularSelection(category) {
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function setBooster(ItemType, ExpiryDate, callback) {
|
||||||
|
revalidateAuthz(() => {
|
||||||
|
$.post({
|
||||||
|
url: "/custom/setBooster?" + window.authz,
|
||||||
|
contentType: "application/json",
|
||||||
|
data: JSON.stringify([
|
||||||
|
{
|
||||||
|
ItemType,
|
||||||
|
ExpiryDate
|
||||||
|
}
|
||||||
|
])
|
||||||
|
}).done(function () {
|
||||||
|
updateInventory();
|
||||||
|
if (callback) callback();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function doAcquireBoosters() {
|
||||||
|
const uniqueName = getKey(document.getElementById("acquire-type-Boosters"));
|
||||||
|
if (!uniqueName) {
|
||||||
|
$("#acquire-type-Boosters").addClass("is-invalid").focus();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const ExpiryDate = Date.now() / 1000 + 3 * 24 * 60 * 60; // default 3 days
|
||||||
|
setBooster(uniqueName, ExpiryDate, () => {
|
||||||
|
$("#acquire-type-Boosters").val("");
|
||||||
|
updateInventory();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function doChangeBoosterExpiry(ItemType, ExpiryDateInput) {
|
||||||
|
console.log("Changing booster expiry for", ItemType, "to", ExpiryDateInput.value);
|
||||||
|
// cast local datetime string to unix timestamp
|
||||||
|
const ExpiryDate = new Date(ExpiryDateInput.value).getTime() / 1000;
|
||||||
|
if (isNaN(ExpiryDate)) {
|
||||||
|
ExpiryDateInput.addClass("is-invalid").focus();
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
setBooster(ItemType, ExpiryDate);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
function formatDatetime(fmt, date) {
|
||||||
|
if (typeof date === "number") date = new Date(date);
|
||||||
|
return fmt.replace(/(%[yY]|%m|%[Dd]|%H|%h|%M|%[Ss]|%[Pp])/g, match => {
|
||||||
|
switch (match) {
|
||||||
|
case "%Y":
|
||||||
|
return date.getFullYear().toString();
|
||||||
|
case "%y":
|
||||||
|
return date.getFullYear().toString().slice(-2);
|
||||||
|
case "%m":
|
||||||
|
return (date.getMonth() + 1).toString().padStart(2, "0");
|
||||||
|
case "%D":
|
||||||
|
case "%d":
|
||||||
|
return date.getDate().toString().padStart(2, "0");
|
||||||
|
case "%H":
|
||||||
|
return date.getHours().toString().padStart(2, "0");
|
||||||
|
case "%h":
|
||||||
|
return (date.getHours() % 12).toString().padStart(2, "0");
|
||||||
|
case "%M":
|
||||||
|
return date.getMinutes().toString().padStart(2, "0");
|
||||||
|
case "%S":
|
||||||
|
case "%s":
|
||||||
|
return date.getSeconds().toString().padStart(2, "0");
|
||||||
|
case "%P":
|
||||||
|
case "%p":
|
||||||
|
return date.getHours() < 12 ? "am" : "pm";
|
||||||
|
default:
|
||||||
|
return match;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
@ -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_inventoryUpdateNote: `Hinweis: Änderungen, die hier vorgenommen werden, werden erst im Spiel angewendet, sobald das Inventar synchronisiert wird. Die Sternenkarte zu besuchen, sollte der einfachste Weg sein, dies auszulösen.`,
|
||||||
general_addButton: `Hinzufügen`,
|
general_addButton: `Hinzufügen`,
|
||||||
general_bulkActions: `Massenaktionen`,
|
general_bulkActions: `Massenaktionen`,
|
||||||
|
code_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_nonValidAuthz: `Deine Anmeldedaten sind nicht mehr gültig.`,
|
||||||
code_changeNameConfirm: `In welchen Namen möchtest du deinen Account umbenennen?`,
|
code_changeNameConfirm: `In welchen Namen möchtest du deinen Account umbenennen?`,
|
||||||
code_deleteAccountConfirm: `Bist du sicher, dass du deinen Account |DISPLAYNAME| (|EMAIL|) löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.`,
|
code_deleteAccountConfirm: `Bist du sicher, dass du deinen Account |DISPLAYNAME| (|EMAIL|) löschen möchtest? Diese Aktion kann nicht rückgängig gemacht werden.`,
|
||||||
@ -63,8 +65,6 @@ dict = {
|
|||||||
navbar_logout: `Abmelden`,
|
navbar_logout: `Abmelden`,
|
||||||
navbar_renameAccount: `Account umbenennen`,
|
navbar_renameAccount: `Account umbenennen`,
|
||||||
navbar_deleteAccount: `Account löschen`,
|
navbar_deleteAccount: `Account löschen`,
|
||||||
navbar_darkTheme: `Dunkles Design`,
|
|
||||||
navbar_lightTheme: `Helles Design`,
|
|
||||||
navbar_inventory: `Inventar`,
|
navbar_inventory: `Inventar`,
|
||||||
navbar_mods: `Mods`,
|
navbar_mods: `Mods`,
|
||||||
navbar_quests: `Quests`,
|
navbar_quests: `Quests`,
|
||||||
@ -100,6 +100,7 @@ dict = {
|
|||||||
inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
|
inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
|
inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
|
||||||
inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`,
|
inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`,
|
||||||
|
inventory_Boosters: `[UNTRANSLATED] Boosters`,
|
||||||
|
|
||||||
quests_list: `Quests`,
|
quests_list: `Quests`,
|
||||||
quests_completeAll: `Alle Quests abschließen`,
|
quests_completeAll: `Alle Quests abschließen`,
|
||||||
@ -165,7 +166,8 @@ dict = {
|
|||||||
cheats_noDojoResearchTime: `Keine Dojo-Forschungszeit`,
|
cheats_noDojoResearchTime: `Keine Dojo-Forschungszeit`,
|
||||||
cheats_fastClanAscension: `Schneller Clan-Aufstieg`,
|
cheats_fastClanAscension: `Schneller Clan-Aufstieg`,
|
||||||
cheats_spoofMasteryRank: `Gefälschter Meisterschaftsrang (-1 zum deaktivieren)`,
|
cheats_spoofMasteryRank: `Gefälschter Meisterschaftsrang (-1 zum deaktivieren)`,
|
||||||
cheats_saveSettings: `Einstellungen speichern`,
|
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
|
||||||
|
cheats_save: `[UNTRANSLATED] Save`,
|
||||||
cheats_account: `Account`,
|
cheats_account: `Account`,
|
||||||
cheats_unlockAllFocusSchools: `Alle Fokus-Schulen freischalten`,
|
cheats_unlockAllFocusSchools: `Alle Fokus-Schulen freischalten`,
|
||||||
cheats_helminthUnlockAll: `Helminth vollständig aufleveln`,
|
cheats_helminthUnlockAll: `Helminth vollständig aufleveln`,
|
||||||
@ -175,5 +177,57 @@ dict = {
|
|||||||
cheats_none: `Keines`,
|
cheats_none: `Keines`,
|
||||||
import_importNote: `Du kannst hier eine vollständige oder teilweise Inventarantwort (Client-Darstellung) einfügen. Alle Felder, die vom Importer unterstützt werden, <b>werden in deinem Account überschrieben</b>.`,
|
import_importNote: `Du kannst hier eine vollständige oder teilweise Inventarantwort (Client-Darstellung) einfügen. Alle Felder, die vom Importer unterstützt werden, <b>werden in deinem Account überschrieben</b>.`,
|
||||||
import_submit: `Absenden`,
|
import_submit: `Absenden`,
|
||||||
|
|
||||||
|
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`,
|
||||||
|
|
||||||
prettier_sucks_ass: ``
|
prettier_sucks_ass: ``
|
||||||
};
|
};
|
||||||
|
@ -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_inventoryUpdateNote: `Note: Changes made here will only be applied in-game when the game syncs the inventory. Visiting the navigation should be the easiest way to trigger that.`,
|
||||||
general_addButton: `Add`,
|
general_addButton: `Add`,
|
||||||
general_bulkActions: `Bulk Actions`,
|
general_bulkActions: `Bulk Actions`,
|
||||||
|
code_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_nonValidAuthz: `Your credentials are no longer valid.`,
|
||||||
code_changeNameConfirm: `What would you like to change your account name to?`,
|
code_changeNameConfirm: `What would you like to change your account name to?`,
|
||||||
code_deleteAccountConfirm: `Are you sure you want to delete your account |DISPLAYNAME| (|EMAIL|)? This action cannot be undone.`,
|
code_deleteAccountConfirm: `Are you sure you want to delete your account |DISPLAYNAME| (|EMAIL|)? This action cannot be undone.`,
|
||||||
@ -62,8 +64,6 @@ dict = {
|
|||||||
navbar_logout: `Logout`,
|
navbar_logout: `Logout`,
|
||||||
navbar_renameAccount: `Rename Account`,
|
navbar_renameAccount: `Rename Account`,
|
||||||
navbar_deleteAccount: `Delete Account`,
|
navbar_deleteAccount: `Delete Account`,
|
||||||
navbar_darkTheme: `Dark Theme`,
|
|
||||||
navbar_lightTheme: `Light Theme`,
|
|
||||||
navbar_inventory: `Inventory`,
|
navbar_inventory: `Inventory`,
|
||||||
navbar_mods: `Mods`,
|
navbar_mods: `Mods`,
|
||||||
navbar_quests: `Quests`,
|
navbar_quests: `Quests`,
|
||||||
@ -99,6 +99,7 @@ dict = {
|
|||||||
inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
|
inventory_bulkRankUpSentinels: `Max Rank All Sentinels`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
|
inventory_bulkRankUpSentinelWeapons: `Max Rank All Sentinel Weapons`,
|
||||||
inventory_bulkRankUpEvolutionProgress: `Max Rank All Incarnon Evolution Progress`,
|
inventory_bulkRankUpEvolutionProgress: `Max Rank All Incarnon Evolution Progress`,
|
||||||
|
inventory_Boosters: `Boosters`,
|
||||||
|
|
||||||
quests_list: `Quests`,
|
quests_list: `Quests`,
|
||||||
quests_completeAll: `Complete All Quests`,
|
quests_completeAll: `Complete All Quests`,
|
||||||
@ -164,7 +165,8 @@ dict = {
|
|||||||
cheats_noDojoResearchTime: `No Dojo Research Time`,
|
cheats_noDojoResearchTime: `No Dojo Research Time`,
|
||||||
cheats_fastClanAscension: `Fast Clan Ascension`,
|
cheats_fastClanAscension: `Fast Clan Ascension`,
|
||||||
cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`,
|
cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`,
|
||||||
cheats_saveSettings: `Save Settings`,
|
cheats_nightwaveStandingMultiplier: `Nightwave Standing Multiplier`,
|
||||||
|
cheats_save: `Save`,
|
||||||
cheats_account: `Account`,
|
cheats_account: `Account`,
|
||||||
cheats_unlockAllFocusSchools: `Unlock All Focus Schools`,
|
cheats_unlockAllFocusSchools: `Unlock All Focus Schools`,
|
||||||
cheats_helminthUnlockAll: `Fully Level Up Helminth`,
|
cheats_helminthUnlockAll: `Fully Level Up Helminth`,
|
||||||
@ -174,5 +176,57 @@ dict = {
|
|||||||
cheats_none: `None`,
|
cheats_none: `None`,
|
||||||
import_importNote: `You can provide a full or partial inventory response (client respresentation) here. All fields that are supported by the importer <b>will be overwritten</b> in your account.`,
|
import_importNote: `You can provide a full or partial inventory response (client respresentation) here. All fields that are supported by the importer <b>will be overwritten</b> in your account.`,
|
||||||
import_submit: `Submit`,
|
import_submit: `Submit`,
|
||||||
|
|
||||||
|
upgrade_Equilibrium: `+|VAL|% Energy from Health pickups, +|VAL|% Health from Energy pickups`,
|
||||||
|
upgrade_MeleeCritDamage: `+|VAL|% Melee Critical Damage`,
|
||||||
|
upgrade_PrimaryStatusChance: `+|VAL|% Primary Status Chance`,
|
||||||
|
upgrade_SecondaryCritChance: `+|VAL|% Secondary Critical Chance`,
|
||||||
|
upgrade_WarframeAbilityDuration: `+|VAL|% Ability Duration`,
|
||||||
|
upgrade_WarframeAbilityStrength: `+|VAL|% Ability Strength`,
|
||||||
|
upgrade_WarframeArmourMax: `+|VAL| Armor`,
|
||||||
|
upgrade_WarframeBlastProc: `+|VAL| Shields on inflicting Blast Status`,
|
||||||
|
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|`,
|
||||||
|
upgrade_WarframeCritDamageBoost: `+|VAL|% Melee Critical Damage (Doubles over 500 Energy)`,
|
||||||
|
upgrade_WarframeElectricDamage: `+|VAL1|% Primary Electricity Damage (+|VAL2|% per additional Shard)`,
|
||||||
|
upgrade_WarframeElectricDamageBoost: `+|VAL|% Ability Damage on enemies affected by Electricity Status`,
|
||||||
|
upgrade_WarframeEnergyMax: `+|VAL| Energy Max`,
|
||||||
|
upgrade_WarframeGlobeEffectEnergy: `+|VAL|% Energy Orb Effectiveness`,
|
||||||
|
upgrade_WarframeGlobeEffectHealth: `+|VAL|% Health Orb Effectiveness`,
|
||||||
|
upgrade_WarframeHealthMax: `+|VAL| Health`,
|
||||||
|
upgrade_WarframeHPBoostFromImpact: `+|VAL1| Health per enemy killed with Blast Damage (Max |VAL2| Health)`,
|
||||||
|
upgrade_WarframeParkourVelocity: `+|VAL|% Parkour Velocity`,
|
||||||
|
upgrade_WarframeRadiationDamageBoost: `+|VAL|% Ability Damage on enemies affected by Radiation Status`,
|
||||||
|
upgrade_WarframeRegen: `+|VAL| Health Regen/s`,
|
||||||
|
upgrade_WarframeShieldMax: `+|VAL| Shield`,
|
||||||
|
upgrade_WarframeStartingEnergy: `+|VAL|% Energy on Spawn`,
|
||||||
|
upgrade_WarframeToxinDamage: `+|VAL|% Toxin Status Effect Damage`,
|
||||||
|
upgrade_WarframeToxinHeal: `+|VAL| Health on damaging enemies with Toxin Status`,
|
||||||
|
upgrade_WeaponCritBoostFromHeat: `+|VAL1|% Secondary Critical Chance per Heat-affected enemy killed (Max |VAL2|%)`,
|
||||||
|
upgrade_AvatarAbilityRange: `+7.5% Ability Range`,
|
||||||
|
upgrade_AvatarAbilityEfficiency: `+5% Ability Efficiency`,
|
||||||
|
upgrade_AvatarEnergyRegen: `+0.5 Energy Regen/s`,
|
||||||
|
upgrade_AvatarEnemyRadar: `+5m Enemy Radar`,
|
||||||
|
upgrade_AvatarLootRadar: `+7m Loot Radar`,
|
||||||
|
upgrade_WeaponAmmoMax: `+15% Ammo Max`,
|
||||||
|
upgrade_EnemyArmorReductionAura: `-3% Enemy Armor`,
|
||||||
|
upgrade_OnExecutionAmmo: `100% Primary and Secondary Magazine Refill on Mercy`,
|
||||||
|
upgrade_OnExecutionHealthDrop: `100% chance to drop a Health Orb on Mercy`,
|
||||||
|
upgrade_OnExecutionEnergyDrop: `50% chance to drop an Energy Orb on Mercy`,
|
||||||
|
upgrade_OnFailHackReset: `+50% to retry on Hacking failure`,
|
||||||
|
upgrade_DamageReductionOnHack: `75% Damage Reduction while Hacking`,
|
||||||
|
upgrade_OnExecutionReviveCompanion: `Mercy Kills reduce Companion Recovery by 15s`,
|
||||||
|
upgrade_OnExecutionParkourSpeed: `+60% Parkour Speed after a Mercy for 15s`,
|
||||||
|
upgrade_AvatarTimeLimitIncrease: `s to Hacking`,
|
||||||
|
upgrade_ElectrifyOnHack: `Shock enemies within 20m while Hacking`,
|
||||||
|
upgrade_OnExecutionTerrify: `50% chance for enemies within 15m to cower in fear for 8 seconds on Mercy`,
|
||||||
|
upgrade_OnHackLockers: `Unlock 5 lockers within 20m after Hacking`,
|
||||||
|
upgrade_OnExecutionBlind: `Blind enemies within 18m on Mercy`,
|
||||||
|
upgrade_OnExecutionDrainPower: `100% chance for next ability cast to gain +50% Ability Strength on Mercy`,
|
||||||
|
upgrade_OnHackSprintSpeed: `+75% Sprint Speed for 15s after Hacking`,
|
||||||
|
upgrade_SwiftExecute: `Speed of Mercy Kills increased by 50%`,
|
||||||
|
upgrade_OnHackInvis: `Invisible for 15 seconds after hacking`,
|
||||||
|
|
||||||
prettier_sucks_ass: ``
|
prettier_sucks_ass: ``
|
||||||
};
|
};
|
||||||
|
@ -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_inventoryUpdateNote: `Nota: Los cambios realizados aquí se reflejarán en el juego cuando este sincronice el inventario. Usar la navegación debería ser la forma más sencilla de activar esto.`,
|
||||||
general_addButton: `Agregar`,
|
general_addButton: `Agregar`,
|
||||||
general_bulkActions: `Acciones masivas`,
|
general_bulkActions: `Acciones masivas`,
|
||||||
|
code_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_nonValidAuthz: `Tus credenciales no son válidas.`,
|
||||||
code_changeNameConfirm: `¿Qué nombre te gustaría ponerle a tu cuenta?`,
|
code_changeNameConfirm: `¿Qué nombre te gustaría ponerle a tu cuenta?`,
|
||||||
code_deleteAccountConfirm: `¿Estás seguro de que deseas eliminar tu cuenta |DISPLAYNAME| (|EMAIL|)? Esta acción es permanente.`,
|
code_deleteAccountConfirm: `¿Estás seguro de que deseas eliminar tu cuenta |DISPLAYNAME| (|EMAIL|)? Esta acción es permanente.`,
|
||||||
@ -63,8 +65,6 @@ dict = {
|
|||||||
navbar_logout: `Cerrar sesión`,
|
navbar_logout: `Cerrar sesión`,
|
||||||
navbar_renameAccount: `Renombrar cuenta`,
|
navbar_renameAccount: `Renombrar cuenta`,
|
||||||
navbar_deleteAccount: `Eliminar cuenta`,
|
navbar_deleteAccount: `Eliminar cuenta`,
|
||||||
navbar_darkTheme: `[UNTRANSLATED] Dark Theme`,
|
|
||||||
navbar_lightTheme: `[UNTRANSLATED] Light Theme`,
|
|
||||||
navbar_inventory: `Inventario`,
|
navbar_inventory: `Inventario`,
|
||||||
navbar_mods: `Mods`,
|
navbar_mods: `Mods`,
|
||||||
navbar_quests: `Misiones`,
|
navbar_quests: `Misiones`,
|
||||||
@ -100,6 +100,7 @@ dict = {
|
|||||||
inventory_bulkRankUpSentinels: `Maximizar rango de todos los centinelas`,
|
inventory_bulkRankUpSentinels: `Maximizar rango de todos los centinelas`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `Maximizar rango de todas las armas de centinela`,
|
inventory_bulkRankUpSentinelWeapons: `Maximizar rango de todas las armas de centinela`,
|
||||||
inventory_bulkRankUpEvolutionProgress: `Maximizar todo el progreso de evolución Incarnon`,
|
inventory_bulkRankUpEvolutionProgress: `Maximizar todo el progreso de evolución Incarnon`,
|
||||||
|
inventory_Boosters: `Potenciadores`,
|
||||||
|
|
||||||
quests_list: `Misiones`,
|
quests_list: `Misiones`,
|
||||||
quests_completeAll: `Completar todas las misiones`,
|
quests_completeAll: `Completar todas las misiones`,
|
||||||
@ -165,7 +166,8 @@ dict = {
|
|||||||
cheats_noDojoResearchTime: `Sin tiempo de investigación del dojo`,
|
cheats_noDojoResearchTime: `Sin tiempo de investigación del dojo`,
|
||||||
cheats_fastClanAscension: `Ascenso rápido del clan`,
|
cheats_fastClanAscension: `Ascenso rápido del clan`,
|
||||||
cheats_spoofMasteryRank: `Rango de maestría simulado (-1 para desactivar)`,
|
cheats_spoofMasteryRank: `Rango de maestría simulado (-1 para desactivar)`,
|
||||||
cheats_saveSettings: `Guardar configuración`,
|
cheats_nightwaveStandingMultiplier: `Multiplicador de Reputación de Onda Nocturna`,
|
||||||
|
cheats_save: `Guardar`,
|
||||||
cheats_account: `Cuenta`,
|
cheats_account: `Cuenta`,
|
||||||
cheats_unlockAllFocusSchools: `Desbloquear todas las escuelas de enfoque`,
|
cheats_unlockAllFocusSchools: `Desbloquear todas las escuelas de enfoque`,
|
||||||
cheats_helminthUnlockAll: `Subir al máximo el Helminto`,
|
cheats_helminthUnlockAll: `Subir al máximo el Helminto`,
|
||||||
@ -175,5 +177,57 @@ dict = {
|
|||||||
cheats_none: `Ninguno`,
|
cheats_none: `Ninguno`,
|
||||||
import_importNote: `Puedes proporcionar una respuesta de inventario completa o parcial (representación del cliente) aquí. Todos los campos compatibles con el importador <b>serán sobrescritos</b> en tu cuenta.`,
|
import_importNote: `Puedes proporcionar una respuesta de inventario completa o parcial (representación del cliente) aquí. Todos los campos compatibles con el importador <b>serán sobrescritos</b> en tu cuenta.`,
|
||||||
import_submit: `Enviar`,
|
import_submit: `Enviar`,
|
||||||
|
|
||||||
|
upgrade_Equilibrium: `+|VAL|% de Energía al recoger salud, +|VAL|% de Salud al recoger energía`,
|
||||||
|
upgrade_MeleeCritDamage: `+|VAL|% de daño crítico cuerpo a cuerpo`,
|
||||||
|
upgrade_PrimaryStatusChance: `+|VAL|% de probabilidad de estado en armas primarias`,
|
||||||
|
upgrade_SecondaryCritChance: `+|VAL|% de probabilidad crítica en armas secundarias`,
|
||||||
|
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_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|`,
|
||||||
|
upgrade_WarframeCritDamageBoost: `+|VAL|% de daño crítico cuerpo a cuerpo (se duplica con más de 500 de energía)`,
|
||||||
|
upgrade_WarframeElectricDamage: `+|VAL1|% de daño eléctrico en armas primarias (+|VAL2|% por fragmento adicional)`,
|
||||||
|
upgrade_WarframeElectricDamageBoost: `+|VAL|% de daño de habilidades a enemigos con estado eléctrico`,
|
||||||
|
upgrade_WarframeEnergyMax: `+|VAL| de energía máxima`,
|
||||||
|
upgrade_WarframeGlobeEffectEnergy: `+|VAL|% de efectividad de orbes de energía`,
|
||||||
|
upgrade_WarframeGlobeEffectHealth: `+|VAL|% de efectividad de orbes de salud`,
|
||||||
|
upgrade_WarframeHealthMax: `+|VAL| de salud máxima`,
|
||||||
|
upgrade_WarframeHPBoostFromImpact: `+|VAL1| de salud por enemigo eliminado con daño explosivo (máximo |VAL2| de salud)`,
|
||||||
|
upgrade_WarframeParkourVelocity: `+|VAL|% de velocidad de parkour`,
|
||||||
|
upgrade_WarframeRadiationDamageBoost: `+|VAL|% de daño de habilidades a enemigos con estado radiactivo`,
|
||||||
|
upgrade_WarframeRegen: `+|VAL| de regeneración de salud por segundo`,
|
||||||
|
upgrade_WarframeShieldMax: `+|VAL| de escudo`,
|
||||||
|
upgrade_WarframeStartingEnergy: `+|VAL|% de energía al reaparecer`,
|
||||||
|
upgrade_WarframeToxinDamage: `+|VAL|% de daño por efecto de estado tóxico`,
|
||||||
|
upgrade_WarframeToxinHeal: `+|VAL| de salud al dañar enemigos con estado tóxico`,
|
||||||
|
upgrade_WeaponCritBoostFromHeat: `+|VAL1|% de probabilidad crítica secundaria por enemigo afectado por calor eliminado (máx. |VAL2|%)`,
|
||||||
|
upgrade_AvatarAbilityRange: `+7.5% de alcance de habilidades`,
|
||||||
|
upgrade_AvatarAbilityEfficiency: `+5% de eficiencia de habilidades`,
|
||||||
|
upgrade_AvatarEnergyRegen: `+0.5 de regeneración de energía por segundo`,
|
||||||
|
upgrade_AvatarEnemyRadar: `+5m de radar de enemigos`,
|
||||||
|
upgrade_AvatarLootRadar: `+7m de radar de botín`,
|
||||||
|
upgrade_WeaponAmmoMax: `+15% de munición máxima`,
|
||||||
|
upgrade_EnemyArmorReductionAura: `-3% de armadura enemiga`,
|
||||||
|
upgrade_OnExecutionAmmo: `Recarga al 100% el cargador primario y secundario tras ejecución (Misericordia)`,
|
||||||
|
upgrade_OnExecutionHealthDrop: `100% de probabilidad de soltar un orbe de salud tras ejecución (Misericordia)`,
|
||||||
|
upgrade_OnExecutionEnergyDrop: `50% de probabilidad de soltar un orbe de energía tras ejecución (Misericordia)`,
|
||||||
|
upgrade_OnFailHackReset: `+50% de probabilidad de reintento al fallar un hackeo`,
|
||||||
|
upgrade_DamageReductionOnHack: `75% de reducción de daño al hackear`,
|
||||||
|
upgrade_OnExecutionReviveCompanion: `Las ejecuciones reducen el tiempo de recuperación del compañero en 15s`,
|
||||||
|
upgrade_OnExecutionParkourSpeed: `+60% de velocidad de parkour durante 15s tras una ejecución`,
|
||||||
|
upgrade_AvatarTimeLimitIncrease: `+|VAL|s al tiempo de hackeo`,
|
||||||
|
upgrade_ElectrifyOnHack: `Electrocuta a los enemigos en un radio de 20m al hackear`,
|
||||||
|
upgrade_OnExecutionTerrify: `50% de probabilidad de que enemigos en un radio de 15m entren en pánico por 8s tras una ejecución`,
|
||||||
|
upgrade_OnHackLockers: `Desbloquea 5 casilleros en un radio de 20m tras hackear`,
|
||||||
|
upgrade_OnExecutionBlind: `Ciega a los enemigos en un radio de 18m tras una ejecución`,
|
||||||
|
upgrade_OnExecutionDrainPower: `100% de probabilidad de que la siguiente habilidad tenga +50% de fuerza tras una ejecución`,
|
||||||
|
upgrade_OnHackSprintSpeed: `+75% de velocidad de carrera durante 15s después de hackear`,
|
||||||
|
upgrade_SwiftExecute: `Velocidad de ejecuciones aumentada en un 50%`,
|
||||||
|
upgrade_OnHackInvis: `Invisible durante 15 segundos después de hackear`,
|
||||||
|
|
||||||
prettier_sucks_ass: ``
|
prettier_sucks_ass: ``
|
||||||
};
|
};
|
||||||
|
@ -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_inventoryUpdateNote: `Note : Les changements effectués ici seront appliqués lors de la syncrhonisation. Visiter la navigation appliquera les changements apportés à l'inventaire.`,
|
||||||
general_addButton: `Ajouter`,
|
general_addButton: `Ajouter`,
|
||||||
general_bulkActions: `Action groupée`,
|
general_bulkActions: `Action groupée`,
|
||||||
|
code_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_nonValidAuthz: `Informations de connexion invalides`,
|
||||||
code_changeNameConfirm: `Nouveau nom du compte :`,
|
code_changeNameConfirm: `Nouveau nom du compte :`,
|
||||||
code_deleteAccountConfirm: `Supprimer |DISPLAYNAME| (|EMAIL|) ? Cette action est irreversible.`,
|
code_deleteAccountConfirm: `Supprimer |DISPLAYNAME| (|EMAIL|) ? Cette action est irreversible.`,
|
||||||
@ -63,8 +65,6 @@ dict = {
|
|||||||
navbar_logout: `Déconnexion`,
|
navbar_logout: `Déconnexion`,
|
||||||
navbar_renameAccount: `Renommer le compte`,
|
navbar_renameAccount: `Renommer le compte`,
|
||||||
navbar_deleteAccount: `Supprimer le compte`,
|
navbar_deleteAccount: `Supprimer le compte`,
|
||||||
navbar_darkTheme: `[UNTRANSLATED] Dark Theme`,
|
|
||||||
navbar_lightTheme: `[UNTRANSLATED] Light Theme`,
|
|
||||||
navbar_inventory: `Inventaire`,
|
navbar_inventory: `Inventaire`,
|
||||||
navbar_mods: `Mods`,
|
navbar_mods: `Mods`,
|
||||||
navbar_quests: `Quêtes`,
|
navbar_quests: `Quêtes`,
|
||||||
@ -100,6 +100,7 @@ dict = {
|
|||||||
inventory_bulkRankUpSentinels: `Toutes les Sentinelles au rang max`,
|
inventory_bulkRankUpSentinels: `Toutes les Sentinelles au rang max`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles au rang max`,
|
inventory_bulkRankUpSentinelWeapons: `Toutes les armes de Sentinelles au rang max`,
|
||||||
inventory_bulkRankUpEvolutionProgress: `Toutes les évolutions Incarnon au rang max`,
|
inventory_bulkRankUpEvolutionProgress: `Toutes les évolutions Incarnon au rang max`,
|
||||||
|
inventory_Boosters: `[UNTRANSLATED] Boosters`,
|
||||||
|
|
||||||
quests_list: `Quêtes`,
|
quests_list: `Quêtes`,
|
||||||
quests_completeAll: `Compléter toutes les quêtes`,
|
quests_completeAll: `Compléter toutes les quêtes`,
|
||||||
@ -165,7 +166,8 @@ dict = {
|
|||||||
cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`,
|
cheats_noDojoResearchTime: `Aucun temps de recherche (Dojo)`,
|
||||||
cheats_fastClanAscension: `Ascension de clan rapide`,
|
cheats_fastClanAscension: `Ascension de clan rapide`,
|
||||||
cheats_spoofMasteryRank: `Rang de maîtrise personnalisé (-1 pour désactiver)`,
|
cheats_spoofMasteryRank: `Rang de maîtrise personnalisé (-1 pour désactiver)`,
|
||||||
cheats_saveSettings: `Sauvegarder les paramètres`,
|
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
|
||||||
|
cheats_save: `[UNTRANSLATED] Save`,
|
||||||
cheats_account: `Compte`,
|
cheats_account: `Compte`,
|
||||||
cheats_unlockAllFocusSchools: `Débloquer toutes les écoles de focus`,
|
cheats_unlockAllFocusSchools: `Débloquer toutes les écoles de focus`,
|
||||||
cheats_helminthUnlockAll: `Helminth niveau max`,
|
cheats_helminthUnlockAll: `Helminth niveau max`,
|
||||||
@ -175,5 +177,57 @@ dict = {
|
|||||||
cheats_none: `Aucun`,
|
cheats_none: `Aucun`,
|
||||||
import_importNote: `Import manuel. Toutes les modifcations supportées par l'inventaire <b>écraseront celles présentes dans la base de données</b>.`,
|
import_importNote: `Import manuel. Toutes les modifcations supportées par l'inventaire <b>écraseront celles présentes dans la base de données</b>.`,
|
||||||
import_submit: `Soumettre`,
|
import_submit: `Soumettre`,
|
||||||
|
|
||||||
|
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`,
|
||||||
|
|
||||||
prettier_sucks_ass: ``
|
prettier_sucks_ass: ``
|
||||||
};
|
};
|
||||||
|
@ -3,6 +3,8 @@ dict = {
|
|||||||
general_inventoryUpdateNote: `Примечание: изменения, внесенные здесь, отобразятся в игре только после повторной загрузки вашего инвентаря. Посещение навигации — самый простой способ этого добиться.`,
|
general_inventoryUpdateNote: `Примечание: изменения, внесенные здесь, отобразятся в игре только после повторной загрузки вашего инвентаря. Посещение навигации — самый простой способ этого добиться.`,
|
||||||
general_addButton: `Добавить`,
|
general_addButton: `Добавить`,
|
||||||
general_bulkActions: `Массовые действия`,
|
general_bulkActions: `Массовые действия`,
|
||||||
|
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
||||||
|
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
|
||||||
code_nonValidAuthz: `Ваши данные больше не действительны.`,
|
code_nonValidAuthz: `Ваши данные больше не действительны.`,
|
||||||
code_changeNameConfirm: `Какое имя вы хотите установить для своей учетной записи?`,
|
code_changeNameConfirm: `Какое имя вы хотите установить для своей учетной записи?`,
|
||||||
code_deleteAccountConfirm: `Вы уверены, что хотите удалить аккаунт |DISPLAYNAME| (|EMAIL|)? Это действие нельзя отменить.`,
|
code_deleteAccountConfirm: `Вы уверены, что хотите удалить аккаунт |DISPLAYNAME| (|EMAIL|)? Это действие нельзя отменить.`,
|
||||||
@ -63,8 +65,6 @@ dict = {
|
|||||||
navbar_logout: `Выйти`,
|
navbar_logout: `Выйти`,
|
||||||
navbar_renameAccount: `Переименовать аккаунт`,
|
navbar_renameAccount: `Переименовать аккаунт`,
|
||||||
navbar_deleteAccount: `Удалить аккаунт`,
|
navbar_deleteAccount: `Удалить аккаунт`,
|
||||||
navbar_darkTheme: `[UNTRANSLATED] Dark Theme`,
|
|
||||||
navbar_lightTheme: `[UNTRANSLATED] Light Theme`,
|
|
||||||
navbar_inventory: `Инвентарь`,
|
navbar_inventory: `Инвентарь`,
|
||||||
navbar_mods: `Моды`,
|
navbar_mods: `Моды`,
|
||||||
navbar_quests: `Квесты`,
|
navbar_quests: `Квесты`,
|
||||||
@ -100,6 +100,7 @@ dict = {
|
|||||||
inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`,
|
inventory_bulkRankUpSentinels: `Максимальный ранг всех стражей`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`,
|
inventory_bulkRankUpSentinelWeapons: `Максимальный ранг всего оружия стражей`,
|
||||||
inventory_bulkRankUpEvolutionProgress: `Максимальный ранг всех эволюций Инкарнонов`,
|
inventory_bulkRankUpEvolutionProgress: `Максимальный ранг всех эволюций Инкарнонов`,
|
||||||
|
inventory_Boosters: `[UNTRANSLATED] Boosters`,
|
||||||
|
|
||||||
quests_list: `Квесты`,
|
quests_list: `Квесты`,
|
||||||
quests_completeAll: `Завершить все квесты`,
|
quests_completeAll: `Завершить все квесты`,
|
||||||
@ -165,7 +166,8 @@ dict = {
|
|||||||
cheats_noDojoResearchTime: `Мгновенные Исследование Додзё`,
|
cheats_noDojoResearchTime: `Мгновенные Исследование Додзё`,
|
||||||
cheats_fastClanAscension: `Мгновенное Вознесение Клана`,
|
cheats_fastClanAscension: `Мгновенное Вознесение Клана`,
|
||||||
cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`,
|
cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`,
|
||||||
cheats_saveSettings: `Сохранить настройки`,
|
cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`,
|
||||||
|
cheats_save: `[UNTRANSLATED] Save`,
|
||||||
cheats_account: `Аккаунт`,
|
cheats_account: `Аккаунт`,
|
||||||
cheats_unlockAllFocusSchools: `Разблокировать все школы фокуса`,
|
cheats_unlockAllFocusSchools: `Разблокировать все школы фокуса`,
|
||||||
cheats_helminthUnlockAll: `Полностью улучшить Гельминта`,
|
cheats_helminthUnlockAll: `Полностью улучшить Гельминта`,
|
||||||
@ -175,5 +177,57 @@ dict = {
|
|||||||
cheats_none: `Отсутствует`,
|
cheats_none: `Отсутствует`,
|
||||||
import_importNote: `Вы можете загрузить полный или частичный ответ инвентаря (клиентское представление) здесь. Все поддерживаемые поля <b>будут перезаписаны</b> в вашем аккаунте.`,
|
import_importNote: `Вы можете загрузить полный или частичный ответ инвентаря (клиентское представление) здесь. Все поддерживаемые поля <b>будут перезаписаны</b> в вашем аккаунте.`,
|
||||||
import_submit: `Отправить`,
|
import_submit: `Отправить`,
|
||||||
|
|
||||||
|
upgrade_Equilibrium: `[UNTRANSLATED] +|VAL|% Energy from Health pickups, +|VAL|% Health from Energy pickups`,
|
||||||
|
upgrade_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`,
|
||||||
|
|
||||||
prettier_sucks_ass: ``
|
prettier_sucks_ass: ``
|
||||||
};
|
};
|
||||||
|
@ -1,8 +1,10 @@
|
|||||||
// Chinese translation by meb154
|
// Chinese translation by meb154 & bishan178
|
||||||
dict = {
|
dict = {
|
||||||
general_inventoryUpdateNote: `注意:此处所做的更改只有在游戏同步仓库后才会生效。您可以通过访问星图来触发仓库更新。`,
|
general_inventoryUpdateNote: `注意:此处所做的更改只有在游戏同步仓库后才会生效。您可以通过访问星图来触发仓库更新。`,
|
||||||
general_addButton: `添加`,
|
general_addButton: `添加`,
|
||||||
general_bulkActions: `批量操作`,
|
general_bulkActions: `批量操作`,
|
||||||
|
code_loginFail: `登录失败。请检查邮箱和密码。`,
|
||||||
|
code_regFail: `注册失败。账号已存在。`,
|
||||||
code_nonValidAuthz: `您的登录凭证已失效。`,
|
code_nonValidAuthz: `您的登录凭证已失效。`,
|
||||||
code_changeNameConfirm: `您想将账户名称更改为什么?`,
|
code_changeNameConfirm: `您想将账户名称更改为什么?`,
|
||||||
code_deleteAccountConfirm: `确定要删除账户 |DISPLAYNAME| (|EMAIL|) 吗?此操作不可撤销。`,
|
code_deleteAccountConfirm: `确定要删除账户 |DISPLAYNAME| (|EMAIL|) 吗?此操作不可撤销。`,
|
||||||
@ -18,53 +20,51 @@ dict = {
|
|||||||
code_kDrive: `K式悬浮板`,
|
code_kDrive: `K式悬浮板`,
|
||||||
code_legendaryCore: `传奇核心`,
|
code_legendaryCore: `传奇核心`,
|
||||||
code_traumaticPeculiar: `创伤怪奇`,
|
code_traumaticPeculiar: `创伤怪奇`,
|
||||||
code_starter: `|MOD| (有瑕疵的)`,
|
code_starter: `|MOD|(有瑕疵的)`,
|
||||||
code_badItem: `(Imposter)`,
|
code_badItem: `(Imposter)`,
|
||||||
code_maxRank: `满级`,
|
code_maxRank: `满级`,
|
||||||
code_rename: `重命名`,
|
code_rename: `重命名`,
|
||||||
code_renamePrompt: `输入新的自定义名称:`,
|
code_renamePrompt: `输入新的自定义名称:`,
|
||||||
code_remove: `移除`,
|
code_remove: `移除`,
|
||||||
code_addItemsConfirm: `确定要向账户添加 |COUNT| 件物品吗?`,
|
code_addItemsConfirm: `确定要向账户添加 |COUNT| 件物品吗?`,
|
||||||
code_succRankUp: `[UNTRANSLATED] Successfully ranked up.`,
|
code_succRankUp: `等级已提升`,
|
||||||
code_noEquipmentToRankUp: `没有可升级的装备。`,
|
code_noEquipmentToRankUp: `没有可升级的装备。`,
|
||||||
code_succAdded: `已成功添加。`,
|
code_succAdded: `已成功添加。`,
|
||||||
code_succRemoved: `[UNTRANSLATED] Successfully removed.`,
|
code_succRemoved: `已成功移除。`,
|
||||||
code_buffsNumber: `增益数量`,
|
code_buffsNumber: `增益数量`,
|
||||||
code_cursesNumber: `负面数量`,
|
code_cursesNumber: `负面数量`,
|
||||||
code_rerollsNumber: `洗卡次数`,
|
code_rerollsNumber: `洗卡次数`,
|
||||||
code_viewStats: `查看属性`,
|
code_viewStats: `查看属性`,
|
||||||
code_rank: `等级`,
|
code_rank: `等级`,
|
||||||
code_rankUp: `[UNTRANSLATED] Rank up`,
|
code_rankUp: `等级提升`,
|
||||||
code_rankDown: `[UNTRANSLATED] Rank down`,
|
code_rankDown: `等级下降`,
|
||||||
code_count: `数量`,
|
code_count: `数量`,
|
||||||
code_focusAllUnlocked: `所有专精学派均已解锁。`,
|
code_focusAllUnlocked: `所有专精学派均已解锁。`,
|
||||||
code_focusUnlocked: `已解锁 |COUNT| 个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新。`,
|
code_focusUnlocked: `已解锁 |COUNT| 个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新。`,
|
||||||
code_addModsConfirm: `确定要向账户添加 |COUNT| 张MOD吗?`,
|
code_addModsConfirm: `确定要向账户添加 |COUNT| 张MOD吗?`,
|
||||||
code_succImport: `导入成功。`,
|
code_succImport: `导入成功。`,
|
||||||
code_gild: `镀金`,
|
code_gild: `镀金`,
|
||||||
code_moa: `恐鸟`,
|
code_moa: `恐鸟`,
|
||||||
code_zanuka: `猎犬`,
|
code_zanuka: `猎犬`,
|
||||||
code_stage: `[UNTRANSLATED] Stage`,
|
code_stage: `阶段`,
|
||||||
code_complete: `[UNTRANSLATED] Complete`,
|
code_complete: `完成`,
|
||||||
code_nextStage: `[UNTRANSLATED] Next stage`,
|
code_nextStage: `下一阶段`,
|
||||||
code_prevStage: `[UNTRANSLATED] Previous stage`,
|
code_prevStage: `上一阶段`,
|
||||||
code_reset: `[UNTRANSLATED] Reset`,
|
code_reset: `重置`,
|
||||||
code_setInactive: `[UNTRANSLATED] Make the quest inactive`,
|
code_setInactive: `使任务处于未激活状态`,
|
||||||
code_completed: `[UNTRANSLATED] Completed`,
|
code_completed: `已完成`,
|
||||||
code_active: `[UNTRANSLATED] Active`,
|
code_active: `正在执行`,
|
||||||
code_pigment: `颜料`,
|
code_pigment: `颜料`,
|
||||||
code_mature: `[UNTRANSLATED] Mature for combat`,
|
code_mature: `成长并战备`,
|
||||||
code_unmature: `[UNTRANSLATED] Regress genetic aging`,
|
code_unmature: `逆转衰老基因`,
|
||||||
login_description: `使用您的 OpenWF 账户凭证登录(与游戏内连接本服务器时使用的昵称相同)。`,
|
login_description: `使用您的 OpenWF 账户凭证登录(与游戏内连接本服务器时使用的昵称相同)。`,
|
||||||
login_emailLabel: `电子邮箱`,
|
login_emailLabel: `电子邮箱`,
|
||||||
login_passwordLabel: `密码`,
|
login_passwordLabel: `密码`,
|
||||||
login_loginButton: `登录`,
|
login_loginButton: `登录`,
|
||||||
login_registerButton: `[UNTRANSLATED] Register`,
|
login_registerButton: `注册账号`,
|
||||||
navbar_logout: `退出登录`,
|
navbar_logout: `退出登录`,
|
||||||
navbar_renameAccount: `重命名账户`,
|
navbar_renameAccount: `重命名账户`,
|
||||||
navbar_deleteAccount: `删除账户`,
|
navbar_deleteAccount: `删除账户`,
|
||||||
navbar_darkTheme: `[UNTRANSLATED] Dark Theme`,
|
|
||||||
navbar_lightTheme: `[UNTRANSLATED] Light Theme`,
|
|
||||||
navbar_inventory: `仓库`,
|
navbar_inventory: `仓库`,
|
||||||
navbar_mods: `Mods`,
|
navbar_mods: `Mods`,
|
||||||
navbar_quests: `任务`,
|
navbar_quests: `任务`,
|
||||||
@ -84,22 +84,23 @@ dict = {
|
|||||||
inventory_operatorAmps: `增幅器`,
|
inventory_operatorAmps: `增幅器`,
|
||||||
inventory_hoverboards: `K式悬浮板`,
|
inventory_hoverboards: `K式悬浮板`,
|
||||||
inventory_moaPets: `恐鸟`,
|
inventory_moaPets: `恐鸟`,
|
||||||
inventory_kubrowPets: `[UNTRANSLATED] Beasts`,
|
inventory_kubrowPets: `动物同伴`,
|
||||||
inventory_evolutionProgress: `[UNTRANSLATED] Incarnon Evolution Progress`,
|
inventory_evolutionProgress: `灵化之源进度`,
|
||||||
inventory_bulkAddSuits: `添加缺失战甲`,
|
inventory_bulkAddSuits: `添加缺失战甲`,
|
||||||
inventory_bulkAddWeapons: `添加缺失武器`,
|
inventory_bulkAddWeapons: `添加缺失武器`,
|
||||||
inventory_bulkAddSpaceSuits: `添加缺失Archwing`,
|
inventory_bulkAddSpaceSuits: `添加缺失Archwing`,
|
||||||
inventory_bulkAddSpaceWeapons: `添加缺失Archwing武器`,
|
inventory_bulkAddSpaceWeapons: `添加缺失Archwing武器`,
|
||||||
inventory_bulkAddSentinels: `添加缺失守护`,
|
inventory_bulkAddSentinels: `添加缺失守护`,
|
||||||
inventory_bulkAddSentinelWeapons: `添加缺失守护武器`,
|
inventory_bulkAddSentinelWeapons: `添加缺失守护武器`,
|
||||||
inventory_bulkAddEvolutionProgress: `[UNTRANSLATED] Add Missing Incarnon Evolution Progress`,
|
inventory_bulkAddEvolutionProgress: `添加缺失的灵化之源`,
|
||||||
inventory_bulkRankUpSuits: `所有战甲升满级`,
|
inventory_bulkRankUpSuits: `所有战甲升满级`,
|
||||||
inventory_bulkRankUpWeapons: `所有武器升满级`,
|
inventory_bulkRankUpWeapons: `所有武器升满级`,
|
||||||
inventory_bulkRankUpSpaceSuits: `所有Archwing升满级`,
|
inventory_bulkRankUpSpaceSuits: `所有Archwing升满级`,
|
||||||
inventory_bulkRankUpSpaceWeapons: `所有Archwing武器升满级`,
|
inventory_bulkRankUpSpaceWeapons: `所有Archwing武器升满级`,
|
||||||
inventory_bulkRankUpSentinels: `所有守护升满级`,
|
inventory_bulkRankUpSentinels: `所有守护升满级`,
|
||||||
inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
|
inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
|
||||||
inventory_bulkRankUpEvolutionProgress: `[UNTRANSLATED] Max Rank All Incarnon Evolution Progress`,
|
inventory_bulkRankUpEvolutionProgress: `所有灵化之源最大等级`,
|
||||||
|
inventory_Boosters: `加成器`,
|
||||||
|
|
||||||
quests_list: `任务`,
|
quests_list: `任务`,
|
||||||
quests_completeAll: `完成所有任务`,
|
quests_completeAll: `完成所有任务`,
|
||||||
@ -113,15 +114,15 @@ dict = {
|
|||||||
currency_owned: `当前拥有 |COUNT|。`,
|
currency_owned: `当前拥有 |COUNT|。`,
|
||||||
powersuit_archonShardsLabel: `执刑官源力石槽位`,
|
powersuit_archonShardsLabel: `执刑官源力石槽位`,
|
||||||
powersuit_archonShardsDescription: `您可以使用这些无限插槽应用各种强化效果`,
|
powersuit_archonShardsDescription: `您可以使用这些无限插槽应用各种强化效果`,
|
||||||
powersuit_archonShardsDescription2: `[UNTRANSLATED] Note that each archon shard takes some time to be applied when loading in.`,
|
powersuit_archonShardsDescription2: `请注意, 在加载时, 每个执政官源力石都需要一定的时间来生效。`,
|
||||||
mods_addRiven: `添加裂罅MOD`,
|
mods_addRiven: `添加裂罅MOD`,
|
||||||
mods_fingerprint: `印记`,
|
mods_fingerprint: `印记`,
|
||||||
mods_fingerprintHelp: `需要印记相关的帮助?`,
|
mods_fingerprintHelp: `需要印记相关的帮助?`,
|
||||||
mods_rivens: `裂罅MOD`,
|
mods_rivens: `裂罅MOD`,
|
||||||
mods_mods: `Mods`,
|
mods_mods: `Mods`,
|
||||||
mods_addMissingUnrankedMods: `[UNTRANSLATED] Add Missing Unranked Mods`,
|
mods_addMissingUnrankedMods: `添加所有缺失的Mods`,
|
||||||
mods_removeUnranked: `[UNTRANSLATED] Remove Unranked Mods`,
|
mods_removeUnranked: `删除所有未升级的Mods`,
|
||||||
mods_addMissingMaxRankMods: `[UNTRANSLATED] Add Missing Max Rank Mods`,
|
mods_addMissingMaxRankMods: `添加所有缺失的满级Mods`,
|
||||||
cheats_administratorRequirement: `您必须是管理员才能使用此功能。要成为管理员,请将 <code>|DISPLAYNAME|</code> 添加到 config.json 的 <code>administratorNames</code> 中。`,
|
cheats_administratorRequirement: `您必须是管理员才能使用此功能。要成为管理员,请将 <code>|DISPLAYNAME|</code> 添加到 config.json 的 <code>administratorNames</code> 中。`,
|
||||||
cheats_server: `服务器`,
|
cheats_server: `服务器`,
|
||||||
cheats_skipTutorial: `跳过教程`,
|
cheats_skipTutorial: `跳过教程`,
|
||||||
@ -133,47 +134,100 @@ dict = {
|
|||||||
cheats_infiniteEndo: `无限内融核心`,
|
cheats_infiniteEndo: `无限内融核心`,
|
||||||
cheats_infiniteRegalAya: `无限御品阿耶`,
|
cheats_infiniteRegalAya: `无限御品阿耶`,
|
||||||
cheats_infiniteHelminthMaterials: `无限Helminth材料`,
|
cheats_infiniteHelminthMaterials: `无限Helminth材料`,
|
||||||
cheats_claimingBlueprintRefundsIngredients: `[UNTRANSLATED] Claiming Blueprint Refunds Ingredients`,
|
cheats_claimingBlueprintRefundsIngredients: `取消蓝图制造时返还材料`,
|
||||||
cheats_dontSubtractVoidTraces: `[UNTRANSLATED] Don't Subtract Void Traces`,
|
cheats_dontSubtractVoidTraces: `虚空光体无消耗`,
|
||||||
cheats_dontSubtractConsumables: `[UNTRANSLATED] Don't Subtract Consumables`,
|
cheats_dontSubtractConsumables: `消耗物品使用时无损耗`,
|
||||||
cheats_unlockAllShipFeatures: `解锁所有飞船功能`,
|
cheats_unlockAllShipFeatures: `解锁所有飞船功能`,
|
||||||
cheats_unlockAllShipDecorations: `解锁所有飞船装饰`,
|
cheats_unlockAllShipDecorations: `解锁所有飞船装饰`,
|
||||||
cheats_unlockAllFlavourItems: `解锁所有<abbr title=\"动画组合、图标、调色板等\">装饰物品</abbr>`,
|
cheats_unlockAllFlavourItems: `解锁所有<abbr title=\"动画组合、图标、调色板等\">装饰物品</abbr>`,
|
||||||
cheats_unlockAllSkins: `解锁所有外观`,
|
cheats_unlockAllSkins: `解锁所有外观`,
|
||||||
cheats_unlockAllCapturaScenes: `解锁所有Captura场景`,
|
cheats_unlockAllCapturaScenes: `解锁所有Captura场景`,
|
||||||
cheats_unlockAllDecoRecipes: `[UNTRANSLATED] Unlock All Dojo Deco Recipes`,
|
cheats_unlockAllDecoRecipes: `解锁所有道场配方`,
|
||||||
cheats_universalPolarityEverywhere: `全局万用极性`,
|
cheats_universalPolarityEverywhere: `全局万用极性`,
|
||||||
cheats_unlockDoubleCapacityPotatoesEverywhere: `全物品自带Orokin反应堆`,
|
cheats_unlockDoubleCapacityPotatoesEverywhere: `全物品自带Orokin反应堆`,
|
||||||
cheats_unlockExilusEverywhere: `全物品自带适配器`,
|
cheats_unlockExilusEverywhere: `全物品自带适配器`,
|
||||||
cheats_unlockArcanesEverywhere: `全物品自带赋能适配器`,
|
cheats_unlockArcanesEverywhere: `全物品自带赋能适配器`,
|
||||||
cheats_noDailyStandingLimits: `无每日声望限制`,
|
cheats_noDailyStandingLimits: `无每日声望限制`,
|
||||||
cheats_noDailyFocusLimit: `[UNTRANSLATED] No Daily Focus Limits`,
|
cheats_noDailyFocusLimit: `指挥官专精无每日获取上限`,
|
||||||
cheats_noArgonCrystalDecay: `[UNTRANSLATED] No Argon Crystal Decay`,
|
cheats_noArgonCrystalDecay: `氩结晶无衰变`,
|
||||||
cheats_noMasteryRankUpCooldown: `[UNTRANSLATED] No Mastery Rank Up Cooldown`,
|
cheats_noMasteryRankUpCooldown: `段位考核无冷却时间`,
|
||||||
cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`,
|
cheats_noVendorPurchaseLimits: `商城或商人无购买限制`,
|
||||||
cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`,
|
cheats_noDeathMarks: `无死亡标记(不会被 Stalker/Grustrag 三霸/Zanuka 猎人等标记)`,
|
||||||
cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`,
|
cheats_noKimCooldowns: `无 KIM 冷却时间`,
|
||||||
cheats_syndicateMissionsRepeatable: `[UNTRANSLATED] Syndicate Missions Repeatable`,
|
cheats_syndicateMissionsRepeatable: `集团任务可重复`,
|
||||||
cheats_instantFinishRivenChallenge: `[UNTRANSLATED] Instant Finish Riven Challenge`,
|
cheats_instantFinishRivenChallenge: `立即完成裂罅挑战`,
|
||||||
cheats_instantResourceExtractorDrones: `即时资源采集无人机`,
|
cheats_instantResourceExtractorDrones: `即时资源采集无人机`,
|
||||||
cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`,
|
cheats_noResourceExtractorDronesDamage: `资源提取器不会损毁`,
|
||||||
cheats_skipClanKeyCrafting: `[UNTRANSLATED] Skip Clan Key Crafting`,
|
cheats_skipClanKeyCrafting: `跳过氏族钥匙制作, 进入道场无需氏族钥匙`,
|
||||||
cheats_noDojoRoomBuildStage: `无视道场房间建造阶段`,
|
cheats_noDojoRoomBuildStage: `无视道场房间建造阶段`,
|
||||||
cheats_noDojoDecoBuildStage: `[UNTRANSLATED] No Dojo Deco Build Stage`,
|
cheats_noDojoDecoBuildStage: `道场装饰建造立即完成`,
|
||||||
cheats_fastDojoRoomDestruction: `快速拆除道场房间`,
|
cheats_fastDojoRoomDestruction: `快速拆除道场房间`,
|
||||||
cheats_noDojoResearchCosts: `无视道场研究消耗`,
|
cheats_noDojoResearchCosts: `无视道场研究消耗`,
|
||||||
cheats_noDojoResearchTime: `无视道场研究时间`,
|
cheats_noDojoResearchTime: `无视道场研究时间`,
|
||||||
cheats_fastClanAscension: `快速升级氏族`,
|
cheats_fastClanAscension: `快速升级氏族`,
|
||||||
cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`,
|
cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`,
|
||||||
cheats_saveSettings: `保存设置`,
|
cheats_nightwaveStandingMultiplier: `午夜电波声望倍率`,
|
||||||
|
cheats_save: `[UNTRANSLATED] Save`,
|
||||||
cheats_account: `账户`,
|
cheats_account: `账户`,
|
||||||
cheats_unlockAllFocusSchools: `解锁所有专精学派`,
|
cheats_unlockAllFocusSchools: `解锁所有专精学派`,
|
||||||
cheats_helminthUnlockAll: `完全升级Helminth`,
|
cheats_helminthUnlockAll: `完全升级Helminth`,
|
||||||
cheats_intrinsicsUnlockAll: `[UNTRANSLATED] Max Rank All Intrinsics`,
|
cheats_intrinsicsUnlockAll: `所有内源之力最大等级`,
|
||||||
cheats_changeSupportedSyndicate: `支持的集团`,
|
cheats_changeSupportedSyndicate: `支持的集团`,
|
||||||
cheats_changeButton: `更改`,
|
cheats_changeButton: `更改`,
|
||||||
cheats_none: `无`,
|
cheats_none: `无`,
|
||||||
import_importNote: `您可以在此处提供完整或部分库存响应(客户端表示)。支持的所有字段<b>将被覆盖</b>到您的账户中。`,
|
import_importNote: `您可以在此处提供完整或部分库存响应(客户端表示)。支持的所有字段<b>将被覆盖</b>到您的账户中。`,
|
||||||
import_submit: `提交`,
|
import_submit: `提交`,
|
||||||
|
|
||||||
|
upgrade_Equilibrium: `+|VAL|% 能量 来自生命球, +|VAL|% 生命 来自能量球`,
|
||||||
|
upgrade_MeleeCritDamage: `+|VAL|% 近战暴击伤害`,
|
||||||
|
upgrade_PrimaryStatusChance: `+|VAL|% 主武器触发几率`,
|
||||||
|
upgrade_SecondaryCritChance: `+|VAL|% 次要武器暴击几率`,
|
||||||
|
upgrade_WarframeAbilityDuration: `+|VAL|% 技能持续时间`,
|
||||||
|
upgrade_WarframeAbilityStrength: `+|VAL|% 技能强度`,
|
||||||
|
upgrade_WarframeArmourMax: `+|VAL| 护甲`,
|
||||||
|
upgrade_WarframeBlastProc: `施加爆炸状态时,护盾 +|VAL|`,
|
||||||
|
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: ``
|
prettier_sucks_ass: ``
|
||||||
};
|
};
|
||||||
|
Loading…
x
Reference in New Issue
Block a user