merge upstream
This commit is contained in:
commit
c22c376828
@ -14,7 +14,9 @@ import {
|
|||||||
addRecipes,
|
addRecipes,
|
||||||
occupySlot,
|
occupySlot,
|
||||||
combineInventoryChanges,
|
combineInventoryChanges,
|
||||||
addKubrowPetPrint
|
addKubrowPetPrint,
|
||||||
|
addPowerSuit,
|
||||||
|
addEquipment
|
||||||
} from "@/src/services/inventoryService";
|
} from "@/src/services/inventoryService";
|
||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { InventorySlot, IPendingRecipeDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { InventorySlot, IPendingRecipeDatabase } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
@ -22,7 +24,7 @@ import { toOid2 } from "@/src/helpers/inventoryHelpers";
|
|||||||
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { IRecipe } from "warframe-public-export-plus";
|
import { IRecipe } from "warframe-public-export-plus";
|
||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import { IEquipmentClient, Status } from "@/src/types/equipmentTypes";
|
import { EquipmentFeatures, IEquipmentClient, Status } from "@/src/types/equipmentTypes";
|
||||||
|
|
||||||
interface IClaimCompletedRecipeRequest {
|
interface IClaimCompletedRecipeRequest {
|
||||||
RecipeIds: IOid[];
|
RecipeIds: IOid[];
|
||||||
@ -124,6 +126,110 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
const pet = inventory.KubrowPets.id(pendingRecipe.KubrowPet!)!;
|
const pet = inventory.KubrowPets.id(pendingRecipe.KubrowPet!)!;
|
||||||
addKubrowPetPrint(inventory, pet, InventoryChanges);
|
addKubrowPetPrint(inventory, pet, InventoryChanges);
|
||||||
} else if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
} else if (recipe.secretIngredientAction != "SIA_UNBRAND") {
|
||||||
|
if (recipe.resultType == "/Lotus/Powersuits/Excalibur/ExcaliburUmbra") {
|
||||||
|
// Quite the special case here...
|
||||||
|
// We don't just get Umbra, but also Skiajati and Umbra Mods. Both items are max rank, potatoed, and with the mods are pre-installed.
|
||||||
|
// Source: https://wiki.warframe.com/w/The_Sacrifice, https://wiki.warframe.com/w/Excalibur/Umbra, https://wiki.warframe.com/w/Skiajati
|
||||||
|
|
||||||
|
const umbraModA = (
|
||||||
|
await addItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModA",
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
`{"lvl":5}`
|
||||||
|
)
|
||||||
|
).Upgrades![0];
|
||||||
|
const umbraModB = (
|
||||||
|
await addItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModB",
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
`{"lvl":5}`
|
||||||
|
)
|
||||||
|
).Upgrades![0];
|
||||||
|
const umbraModC = (
|
||||||
|
await addItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Upgrades/Mods/Sets/Umbra/WarframeUmbraModC",
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
`{"lvl":5}`
|
||||||
|
)
|
||||||
|
).Upgrades![0];
|
||||||
|
const sacrificeModA = (
|
||||||
|
await addItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Upgrades/Mods/Sets/Sacrifice/MeleeSacrificeModA",
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
`{"lvl":5}`
|
||||||
|
)
|
||||||
|
).Upgrades![0];
|
||||||
|
const sacrificeModB = (
|
||||||
|
await addItem(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Upgrades/Mods/Sets/Sacrifice/MeleeSacrificeModB",
|
||||||
|
1,
|
||||||
|
false,
|
||||||
|
undefined,
|
||||||
|
`{"lvl":5}`
|
||||||
|
)
|
||||||
|
).Upgrades![0];
|
||||||
|
InventoryChanges.Upgrades ??= [];
|
||||||
|
InventoryChanges.Upgrades.push(umbraModA, umbraModB, umbraModC, sacrificeModA, sacrificeModB);
|
||||||
|
|
||||||
|
await addPowerSuit(
|
||||||
|
inventory,
|
||||||
|
"/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
|
||||||
|
{
|
||||||
|
Configs: [
|
||||||
|
{
|
||||||
|
Upgrades: [
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
"",
|
||||||
|
umbraModA.ItemId.$oid,
|
||||||
|
umbraModB.ItemId.$oid,
|
||||||
|
umbraModC.ItemId.$oid
|
||||||
|
]
|
||||||
|
}
|
||||||
|
],
|
||||||
|
XP: 900_000,
|
||||||
|
Features: EquipmentFeatures.DOUBLE_CAPACITY
|
||||||
|
},
|
||||||
|
InventoryChanges
|
||||||
|
);
|
||||||
|
inventory.XPInfo.push({
|
||||||
|
ItemType: "/Lotus/Powersuits/Excalibur/ExcaliburUmbra",
|
||||||
|
XP: 900_000
|
||||||
|
});
|
||||||
|
|
||||||
|
addEquipment(
|
||||||
|
inventory,
|
||||||
|
"Melee",
|
||||||
|
"/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
|
||||||
|
{
|
||||||
|
Configs: [
|
||||||
|
{ Upgrades: ["", "", "", "", "", "", sacrificeModA.ItemId.$oid, sacrificeModB.ItemId.$oid] }
|
||||||
|
],
|
||||||
|
XP: 450_000,
|
||||||
|
Features: EquipmentFeatures.DOUBLE_CAPACITY
|
||||||
|
},
|
||||||
|
InventoryChanges
|
||||||
|
);
|
||||||
|
inventory.XPInfo.push({
|
||||||
|
ItemType: "/Lotus/Weapons/Tenno/Melee/Swords/UmbraKatana/UmbraKatana",
|
||||||
|
XP: 450_000
|
||||||
|
});
|
||||||
|
} else {
|
||||||
InventoryChanges = {
|
InventoryChanges = {
|
||||||
...InventoryChanges,
|
...InventoryChanges,
|
||||||
...(await addItem(
|
...(await addItem(
|
||||||
@ -136,6 +242,7 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
))
|
))
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
}
|
||||||
if (
|
if (
|
||||||
config.claimingBlueprintRefundsIngredients &&
|
config.claimingBlueprintRefundsIngredients &&
|
||||||
recipe.secretIngredientAction != "SIA_CREATE_KUBROW" // Can't refund the egg
|
recipe.secretIngredientAction != "SIA_CREATE_KUBROW" // Can't refund the egg
|
||||||
|
@ -2,7 +2,7 @@ import { getAccountIdForRequest } from "@/src/services/loginService";
|
|||||||
import { getInventory, updateCurrency, updateSlots } from "@/src/services/inventoryService";
|
import { getInventory, updateCurrency, updateSlots } from "@/src/services/inventoryService";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { exhaustive } from "@/src/utils/ts-utils";
|
||||||
|
|
||||||
/*
|
/*
|
||||||
loadout slots are additionally purchased slots only
|
loadout slots are additionally purchased slots only
|
||||||
@ -22,13 +22,44 @@ export const inventorySlotsController: RequestHandler = async (req, res) => {
|
|||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const body = JSON.parse(req.body as string) as IInventorySlotsRequest;
|
const body = JSON.parse(req.body as string) as IInventorySlotsRequest;
|
||||||
|
|
||||||
if (body.Bin != InventorySlot.SUITS && body.Bin != InventorySlot.PVE_LOADOUTS) {
|
let price;
|
||||||
logger.warn(`unexpected slot purchase of type ${body.Bin}, account may be overcharged`);
|
let amount;
|
||||||
|
switch (body.Bin) {
|
||||||
|
case InventorySlot.SUITS:
|
||||||
|
case InventorySlot.MECHSUITS:
|
||||||
|
case InventorySlot.PVE_LOADOUTS:
|
||||||
|
case InventorySlot.CREWMEMBERS:
|
||||||
|
price = 20;
|
||||||
|
amount = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InventorySlot.SPACESUITS:
|
||||||
|
price = 12;
|
||||||
|
amount = 1;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InventorySlot.WEAPONS:
|
||||||
|
case InventorySlot.SPACEWEAPONS:
|
||||||
|
case InventorySlot.SENTINELS:
|
||||||
|
case InventorySlot.RJ_COMPONENT_AND_ARMAMENTS:
|
||||||
|
case InventorySlot.AMPS:
|
||||||
|
price = 12;
|
||||||
|
amount = 2;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case InventorySlot.RIVENS:
|
||||||
|
price = 60;
|
||||||
|
amount = 3;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
exhaustive(body.Bin);
|
||||||
|
throw new Error(`unexpected slot purchase of type ${body.Bin as string}`);
|
||||||
}
|
}
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
const currencyChanges = updateCurrency(inventory, 20, true);
|
const currencyChanges = updateCurrency(inventory, price, true);
|
||||||
updateSlots(inventory, body.Bin, 1, 1);
|
updateSlots(inventory, body.Bin, amount, amount);
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
|
|
||||||
res.json({ InventoryChanges: currencyChanges });
|
res.json({ InventoryChanges: currencyChanges });
|
||||||
|
@ -1,25 +1,39 @@
|
|||||||
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
import { getInventory } from "@/src/services/inventoryService";
|
import { addConsumables, getInventory } from "@/src/services/inventoryService";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { IPlayerSkills } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { IPlayerSkills } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
export const playerSkillsController: RequestHandler = async (req, res) => {
|
export const playerSkillsController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
const inventory = await getInventory(accountId, "PlayerSkills");
|
const inventory = await getInventory(accountId, "PlayerSkills Consumables");
|
||||||
const request = getJSONfromString<IPlayerSkillsRequest>(String(req.body));
|
const request = getJSONfromString<IPlayerSkillsRequest>(String(req.body));
|
||||||
|
|
||||||
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
|
const oldRank: number = inventory.PlayerSkills[request.Skill as keyof IPlayerSkills];
|
||||||
const cost = (request.Pool == "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000;
|
const cost = (request.Pool == "LPP_DRIFTER" ? drifterCosts[oldRank] : 1 << oldRank) * 1000;
|
||||||
inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
|
inventory.PlayerSkills[request.Pool as keyof IPlayerSkills] -= cost;
|
||||||
inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
|
inventory.PlayerSkills[request.Skill as keyof IPlayerSkills]++;
|
||||||
await inventory.save();
|
|
||||||
|
|
||||||
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
|
if (request.Skill == "LPS_COMMAND" && inventory.PlayerSkills.LPS_COMMAND == 9) {
|
||||||
|
const consumablesChanges = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Restoratives/Consumable/CrewmateBall",
|
||||||
|
ItemCount: 1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addConsumables(inventory, consumablesChanges);
|
||||||
|
inventoryChanges.Consumables = consumablesChanges;
|
||||||
|
}
|
||||||
|
|
||||||
|
await inventory.save();
|
||||||
res.json({
|
res.json({
|
||||||
Pool: request.Pool,
|
Pool: request.Pool,
|
||||||
PoolInc: -cost,
|
PoolInc: -cost,
|
||||||
Skill: request.Skill,
|
Skill: request.Skill,
|
||||||
Rank: oldRank + 1
|
Rank: oldRank + 1,
|
||||||
|
InventoryChanges: inventoryChanges
|
||||||
});
|
});
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -23,10 +23,16 @@ export const crackRelic = async (
|
|||||||
weights = { COMMON: 0, UNCOMMON: 0, RARE: 1, LEGENDARY: 0 };
|
weights = { COMMON: 0, UNCOMMON: 0, RARE: 1, LEGENDARY: 0 };
|
||||||
}
|
}
|
||||||
logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights);
|
logger.debug(`opening a relic of quality ${relic.quality}; rarity weights are`, weights);
|
||||||
const reward = getRandomWeightedReward(
|
let reward = getRandomWeightedReward(
|
||||||
ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics
|
ExportRewards[relic.rewardManifest][0] as { type: string; itemCount: number; rarity: TRarity }[], // rarity is nullable in PE+ typings, but always present for relics
|
||||||
weights
|
weights
|
||||||
)!;
|
)!;
|
||||||
|
if (config.relicRewardItemCountMultiplier !== undefined && (config.relicRewardItemCountMultiplier ?? 1) != 1) {
|
||||||
|
reward = {
|
||||||
|
...reward,
|
||||||
|
itemCount: reward.itemCount * config.relicRewardItemCountMultiplier
|
||||||
|
};
|
||||||
|
}
|
||||||
logger.debug(`relic rolled`, reward);
|
logger.debug(`relic rolled`, reward);
|
||||||
participant.Reward = reward.type;
|
participant.Reward = reward.type;
|
||||||
|
|
||||||
@ -43,13 +49,7 @@ export const crackRelic = async (
|
|||||||
// Give reward
|
// Give reward
|
||||||
combineInventoryChanges(
|
combineInventoryChanges(
|
||||||
inventoryChanges,
|
inventoryChanges,
|
||||||
(
|
(await handleStoreItemAcquisition(reward.type, inventory, reward.itemCount)).InventoryChanges
|
||||||
await handleStoreItemAcquisition(
|
|
||||||
reward.type,
|
|
||||||
inventory,
|
|
||||||
reward.itemCount * (config.relicRewardItemCountMultiplier ?? 1)
|
|
||||||
)
|
|
||||||
).InventoryChanges
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return reward;
|
return reward;
|
||||||
|
@ -482,11 +482,14 @@ export const addItem = async (
|
|||||||
if (quantity != 1) {
|
if (quantity != 1) {
|
||||||
logger.warn(`adding 1 of ${typeName} ${targetFingerprint} even tho quantity ${quantity} was requested`);
|
logger.warn(`adding 1 of ${typeName} ${targetFingerprint} even tho quantity ${quantity} was requested`);
|
||||||
}
|
}
|
||||||
|
const upgrade =
|
||||||
|
inventory.Upgrades[
|
||||||
inventory.Upgrades.push({
|
inventory.Upgrades.push({
|
||||||
ItemType: typeName,
|
ItemType: typeName,
|
||||||
UpgradeFingerprint: targetFingerprint
|
UpgradeFingerprint: targetFingerprint
|
||||||
});
|
}) - 1
|
||||||
return {}; // there's not exactly a common "InventoryChanges" format for these
|
];
|
||||||
|
return { Upgrades: [upgrade.toJSON<IUpgradeClient>()] };
|
||||||
}
|
}
|
||||||
const changes = [
|
const changes = [
|
||||||
{
|
{
|
||||||
@ -812,7 +815,7 @@ export const addItem = async (
|
|||||||
if (!seed) {
|
if (!seed) {
|
||||||
throw new Error(`Expected crew member to have a seed`);
|
throw new Error(`Expected crew member to have a seed`);
|
||||||
}
|
}
|
||||||
seed |= 0x33b81en << 32n;
|
seed |= BigInt(Math.trunc(inventory.Created.getTime() / 1000) & 0xffffff) << 32n;
|
||||||
return {
|
return {
|
||||||
...addCrewMember(inventory, typeName, seed),
|
...addCrewMember(inventory, typeName, seed),
|
||||||
...occupySlot(inventory, InventorySlot.CREWMEMBERS, premiumPurchase)
|
...occupySlot(inventory, InventorySlot.CREWMEMBERS, premiumPurchase)
|
||||||
@ -1106,6 +1109,10 @@ export const addKubrowPet = (
|
|||||||
};
|
};
|
||||||
} else {
|
} else {
|
||||||
dominantTraits = createRandomTraits(kubrowPetName, traitsPool);
|
dominantTraits = createRandomTraits(kubrowPetName, traitsPool);
|
||||||
|
if (kubrowPetName == "/Lotus/Types/Game/KubrowPet/ChargerKubrowPetPowerSuit") {
|
||||||
|
dominantTraits.BodyType = "/Lotus/Types/Game/KubrowPet/BodyTypes/ChargerKubrowPetBodyType";
|
||||||
|
dominantTraits.FurPattern = "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternInfested";
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const recessiveTraits: ITraits = createRandomTraits(
|
const recessiveTraits: ITraits = createRandomTraits(
|
||||||
|
@ -236,7 +236,7 @@ const handleQuestCompletion = async (
|
|||||||
setupKahlSyndicate(inventory);
|
setupKahlSyndicate(inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Whispers in the Walls is unlocked once The New + Heart of Deimos are completed.
|
// Whispers in the Walls is unlocked once The New War + Heart of Deimos are completed.
|
||||||
if (
|
if (
|
||||||
doesQuestCompletionFinishSet(inventory, questKey, [
|
doesQuestCompletionFinishSet(inventory, questKey, [
|
||||||
"/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain",
|
"/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain",
|
||||||
|
@ -971,25 +971,26 @@ 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.
|
// 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 = {
|
const voidStormMissions = {
|
||||||
VoidT1: ["CrewBattleNode519", "CrewBattleNode518", "CrewBattleNode515", "CrewBattleNode503"],
|
VoidT1: [
|
||||||
VoidT2: ["CrewBattleNode501", "CrewBattleNode534", "CrewBattleNode530"],
|
"CrewBattleNode519",
|
||||||
VoidT3: ["CrewBattleNode521", "CrewBattleNode516"],
|
"CrewBattleNode518",
|
||||||
|
"CrewBattleNode515",
|
||||||
|
"CrewBattleNode503",
|
||||||
|
"CrewBattleNode509",
|
||||||
|
"CrewBattleNode522",
|
||||||
|
"CrewBattleNode511",
|
||||||
|
"CrewBattleNode512"
|
||||||
|
],
|
||||||
|
VoidT2: ["CrewBattleNode501", "CrewBattleNode534", "CrewBattleNode530", "CrewBattleNode535", "CrewBattleNode533"],
|
||||||
|
VoidT3: ["CrewBattleNode521", "CrewBattleNode516", "CrewBattleNode524", "CrewBattleNode525"],
|
||||||
VoidT4: [
|
VoidT4: [
|
||||||
"CrewBattleNode555",
|
"CrewBattleNode555",
|
||||||
"CrewBattleNode553",
|
"CrewBattleNode553",
|
||||||
"CrewBattleNode554",
|
"CrewBattleNode554",
|
||||||
"CrewBattleNode539",
|
"CrewBattleNode539",
|
||||||
"CrewBattleNode531",
|
"CrewBattleNode531",
|
||||||
"CrewBattleNode527"
|
"CrewBattleNode527",
|
||||||
]
|
|
||||||
};
|
|
||||||
|
|
||||||
const voidStormMissionsB = {
|
|
||||||
VoidT1: ["CrewBattleNode509", "CrewBattleNode522", "CrewBattleNode511", "CrewBattleNode512"],
|
|
||||||
VoidT2: ["CrewBattleNode535", "CrewBattleNode533"],
|
|
||||||
VoidT3: ["CrewBattleNode524", "CrewBattleNode525"],
|
|
||||||
VoidT4: [
|
|
||||||
"CrewBattleNode542",
|
"CrewBattleNode542",
|
||||||
"CrewBattleNode538",
|
"CrewBattleNode538",
|
||||||
"CrewBattleNode543",
|
"CrewBattleNode543",
|
||||||
@ -997,18 +998,21 @@ const voidStormMissionsB = {
|
|||||||
"CrewBattleNode550",
|
"CrewBattleNode550",
|
||||||
"CrewBattleNode529"
|
"CrewBattleNode529"
|
||||||
]
|
]
|
||||||
};
|
} as const;
|
||||||
|
|
||||||
|
const voidStormLookbehind = {
|
||||||
|
VoidT1: 3,
|
||||||
|
VoidT2: 1,
|
||||||
|
VoidT3: 1,
|
||||||
|
VoidT4: 3
|
||||||
|
} as const;
|
||||||
|
|
||||||
const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => {
|
const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => {
|
||||||
const activation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute;
|
const activation = hour * unixTimesInMs.hour + 40 * unixTimesInMs.minute;
|
||||||
const expiry = activation + 90 * unixTimesInMs.minute;
|
const expiry = activation + 90 * unixTimesInMs.minute;
|
||||||
let accum = 0;
|
let accum = 0;
|
||||||
const rng = new SRng(new SRng(hour).randomInt(0, 100_000));
|
const tierIdx = { VoidT1: hour * 2, VoidT2: hour, VoidT3: hour, VoidT4: hour * 2 };
|
||||||
const voidStormMissions = structuredClone(hour & 1 ? voidStormMissionsA : voidStormMissionsB);
|
|
||||||
for (const tier of ["VoidT1", "VoidT1", "VoidT2", "VoidT3", "VoidT4", "VoidT4"] as const) {
|
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({
|
arr.push({
|
||||||
_id: {
|
_id: {
|
||||||
$oid:
|
$oid:
|
||||||
@ -1016,7 +1020,12 @@ const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => {
|
|||||||
"0321e89b" +
|
"0321e89b" +
|
||||||
(accum++).toString().padStart(8, "0")
|
(accum++).toString().padStart(8, "0")
|
||||||
},
|
},
|
||||||
Node: node,
|
Node: sequentiallyUniqueRandomElement(
|
||||||
|
voidStormMissions[tier],
|
||||||
|
tierIdx[tier]++,
|
||||||
|
voidStormLookbehind[tier],
|
||||||
|
2051969264
|
||||||
|
)!,
|
||||||
Activation: { $date: { $numberLong: activation.toString() } },
|
Activation: { $date: { $numberLong: activation.toString() } },
|
||||||
Expiry: { $date: { $numberLong: expiry.toString() } },
|
Expiry: { $date: { $numberLong: expiry.toString() } },
|
||||||
ActiveMissionTier: tier
|
ActiveMissionTier: tier
|
||||||
@ -1024,75 +1033,124 @@ const pushVoidStorms = (arr: IVoidStorm[], hour: number): void => {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const doesTimeSatsifyConstraints = (timeSecs: number): boolean => {
|
interface ITimeConstraint {
|
||||||
if (config.worldState?.eidolonOverride) {
|
//name: string;
|
||||||
|
isValidTime: (timeSecs: number) => boolean;
|
||||||
|
getIdealTimeBefore: (timeSecs: number) => number;
|
||||||
|
}
|
||||||
|
|
||||||
|
const eidolonDayConstraint: ITimeConstraint = {
|
||||||
|
//name: "eidolon day",
|
||||||
|
isValidTime: (timeSecs: number): boolean => {
|
||||||
const eidolonEpoch = 1391992660;
|
const eidolonEpoch = 1391992660;
|
||||||
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
|
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
|
||||||
const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000;
|
const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000;
|
||||||
const eidolonCycleEnd = eidolonCycleStart + 9000;
|
const eidolonCycleEnd = eidolonCycleStart + 9000;
|
||||||
const eidolonCycleNightStart = eidolonCycleEnd - 3000;
|
const eidolonCycleNightStart = eidolonCycleEnd - 3000;
|
||||||
if (config.worldState.eidolonOverride == "day") {
|
return !isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleNightStart * 1000);
|
||||||
if (
|
},
|
||||||
//timeSecs < eidolonCycleStart ||
|
getIdealTimeBefore: (timeSecs: number): number => {
|
||||||
isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleNightStart * 1000)
|
const eidolonEpoch = 1391992660;
|
||||||
) {
|
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
|
||||||
return false;
|
const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000;
|
||||||
}
|
return eidolonCycleStart;
|
||||||
} else {
|
|
||||||
if (
|
|
||||||
timeSecs < eidolonCycleNightStart ||
|
|
||||||
isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleEnd * 1000)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (config.worldState?.vallisOverride) {
|
const eidolonNightConstraint: ITimeConstraint = {
|
||||||
|
//name: "eidolon night",
|
||||||
|
isValidTime: (timeSecs: number): boolean => {
|
||||||
|
const eidolonEpoch = 1391992660;
|
||||||
|
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
|
||||||
|
const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000;
|
||||||
|
const eidolonCycleEnd = eidolonCycleStart + 9000;
|
||||||
|
const eidolonCycleNightStart = eidolonCycleEnd - 3000;
|
||||||
|
return (
|
||||||
|
timeSecs >= eidolonCycleNightStart &&
|
||||||
|
!isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, eidolonCycleEnd * 1000)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
getIdealTimeBefore: (timeSecs: number): number => {
|
||||||
|
const eidolonEpoch = 1391992660;
|
||||||
|
const eidolonCycle = Math.trunc((timeSecs - eidolonEpoch) / 9000);
|
||||||
|
const eidolonCycleStart = eidolonEpoch + eidolonCycle * 9000;
|
||||||
|
const eidolonCycleEnd = eidolonCycleStart + 9000;
|
||||||
|
const eidolonCycleNightStart = eidolonCycleEnd - 3000;
|
||||||
|
if (eidolonCycleNightStart > timeSecs) {
|
||||||
|
// Night hasn't started yet, but we need to return a time in the past.
|
||||||
|
return eidolonCycleNightStart - 9000;
|
||||||
|
}
|
||||||
|
return eidolonCycleNightStart;
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
const venusColdConstraint: ITimeConstraint = {
|
||||||
|
//name: "venus cold",
|
||||||
|
isValidTime: (timeSecs: number): boolean => {
|
||||||
const vallisEpoch = 1541837628;
|
const vallisEpoch = 1541837628;
|
||||||
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
|
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
|
||||||
const vallisCycleStart = vallisEpoch + vallisCycle * 1600;
|
const vallisCycleStart = vallisEpoch + vallisCycle * 1600;
|
||||||
const vallisCycleEnd = vallisCycleStart + 1600;
|
const vallisCycleEnd = vallisCycleStart + 1600;
|
||||||
const vallisCycleColdStart = vallisCycleStart + 400;
|
const vallisCycleColdStart = vallisCycleStart + 400;
|
||||||
if (config.worldState.vallisOverride == "cold") {
|
return (
|
||||||
if (
|
timeSecs >= vallisCycleColdStart &&
|
||||||
timeSecs < vallisCycleColdStart ||
|
!isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleEnd * 1000)
|
||||||
isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleEnd * 1000)
|
);
|
||||||
) {
|
},
|
||||||
return false;
|
getIdealTimeBefore: (timeSecs: number): number => {
|
||||||
}
|
const vallisEpoch = 1541837628;
|
||||||
} else {
|
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
|
||||||
if (
|
const vallisCycleStart = vallisEpoch + vallisCycle * 1600;
|
||||||
//timeSecs < vallisCycleStart ||
|
const vallisCycleColdStart = vallisCycleStart + 400;
|
||||||
isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleColdStart * 1000)
|
if (vallisCycleColdStart > timeSecs) {
|
||||||
) {
|
// Cold hasn't started yet, but we need to return a time in the past.
|
||||||
return false;
|
return vallisCycleColdStart - 1600;
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
return vallisCycleColdStart;
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
if (config.worldState?.duviriOverride) {
|
const venusWarmConstraint: ITimeConstraint = {
|
||||||
const duviriMoods = ["sorrow", "fear", "joy", "anger", "envy"];
|
//name: "venus warm",
|
||||||
const desiredMood = duviriMoods.indexOf(config.worldState.duviriOverride);
|
isValidTime: (timeSecs: number): boolean => {
|
||||||
if (desiredMood == -1) {
|
const vallisEpoch = 1541837628;
|
||||||
logger.warn(`ignoring invalid config value for worldState.duviriOverride`, {
|
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
|
||||||
value: config.worldState.duviriOverride,
|
const vallisCycleStart = vallisEpoch + vallisCycle * 1600;
|
||||||
valid_values: duviriMoods
|
const vallisCycleColdStart = vallisCycleStart + 400;
|
||||||
});
|
return !isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, vallisCycleColdStart * 1000);
|
||||||
} else {
|
},
|
||||||
const moodIndex = Math.trunc(timeSecs / 7200);
|
getIdealTimeBefore: (timeSecs: number): number => {
|
||||||
const moodStart = moodIndex * 7200;
|
const vallisEpoch = 1541837628;
|
||||||
const moodEnd = moodStart + 7200;
|
const vallisCycle = Math.trunc((timeSecs - vallisEpoch) / 1600);
|
||||||
if (
|
const vallisCycleStart = vallisEpoch + vallisCycle * 1600;
|
||||||
moodIndex % 5 != desiredMood ||
|
return vallisCycleStart;
|
||||||
isBeforeNextExpectedWorldStateRefresh(timeSecs * 1000, moodEnd * 1000)
|
|
||||||
) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
};
|
||||||
|
|
||||||
return true;
|
const getIdealTimeSatsifyingConstraints = (constraints: ITimeConstraint[]): number => {
|
||||||
|
let timeSecs = Math.trunc(Date.now() / 1000);
|
||||||
|
let allGood;
|
||||||
|
do {
|
||||||
|
allGood = true;
|
||||||
|
for (const constraint of constraints) {
|
||||||
|
if (!constraint.isValidTime(timeSecs)) {
|
||||||
|
//logger.debug(`${constraint.name} is not happy with ${timeSecs}`);
|
||||||
|
const prevTimeSecs = timeSecs;
|
||||||
|
const suggestion = constraint.getIdealTimeBefore(timeSecs);
|
||||||
|
timeSecs = suggestion;
|
||||||
|
do {
|
||||||
|
timeSecs += 60;
|
||||||
|
if (timeSecs >= prevTimeSecs || !constraint.isValidTime(timeSecs)) {
|
||||||
|
timeSecs = suggestion; // Can't find a compromise; just take the suggestion and try to compromise on another constraint.
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
} while (!constraints.every(constraint => constraint.isValidTime(timeSecs)));
|
||||||
|
allGood = false;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} while (!allGood);
|
||||||
|
return timeSecs;
|
||||||
};
|
};
|
||||||
|
|
||||||
const getVarziaRotation = (week: number): string => {
|
const getVarziaRotation = (week: number): string => {
|
||||||
@ -1170,10 +1228,38 @@ const getAllVarziaManifests = (): IPrimeVaultTraderOffer[] => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
export const getWorldState = (buildLabel?: string): IWorldState => {
|
export const getWorldState = (buildLabel?: string): IWorldState => {
|
||||||
let timeSecs = Math.round(Date.now() / 1000);
|
const constraints: ITimeConstraint[] = [];
|
||||||
while (!doesTimeSatsifyConstraints(timeSecs)) {
|
if (config.worldState?.eidolonOverride) {
|
||||||
timeSecs -= 60;
|
constraints.push(config.worldState.eidolonOverride == "day" ? eidolonDayConstraint : eidolonNightConstraint);
|
||||||
}
|
}
|
||||||
|
if (config.worldState?.vallisOverride) {
|
||||||
|
constraints.push(config.worldState.vallisOverride == "cold" ? venusColdConstraint : venusWarmConstraint);
|
||||||
|
}
|
||||||
|
if (config.worldState?.duviriOverride) {
|
||||||
|
const duviriMoods = ["sorrow", "fear", "joy", "anger", "envy"];
|
||||||
|
const desiredMood = duviriMoods.indexOf(config.worldState.duviriOverride);
|
||||||
|
if (desiredMood == -1) {
|
||||||
|
logger.warn(`ignoring invalid config value for worldState.duviriOverride`, {
|
||||||
|
value: config.worldState.duviriOverride,
|
||||||
|
valid_values: duviriMoods
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
constraints.push({
|
||||||
|
//name: `duviri ${config.worldState.duviriOverride}`,
|
||||||
|
isValidTime: (timeSecs: number): boolean => {
|
||||||
|
const moodIndex = Math.trunc(timeSecs / 7200);
|
||||||
|
return moodIndex % 5 == desiredMood;
|
||||||
|
},
|
||||||
|
getIdealTimeBefore: (timeSecs: number): number => {
|
||||||
|
let moodIndex = Math.trunc(timeSecs / 7200);
|
||||||
|
moodIndex -= ((moodIndex % 5) - desiredMood + 5) % 5; // while (moodIndex % 5 != desiredMood) --moodIndex;
|
||||||
|
const moodStart = moodIndex * 7200;
|
||||||
|
return moodStart;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
const timeSecs = getIdealTimeSatsifyingConstraints(constraints);
|
||||||
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);
|
||||||
|
@ -520,7 +520,8 @@ export enum InventorySlot {
|
|||||||
SENTINELS = "SentinelBin",
|
SENTINELS = "SentinelBin",
|
||||||
AMPS = "OperatorAmpBin",
|
AMPS = "OperatorAmpBin",
|
||||||
RJ_COMPONENT_AND_ARMAMENTS = "CrewShipSalvageBin",
|
RJ_COMPONENT_AND_ARMAMENTS = "CrewShipSalvageBin",
|
||||||
CREWMEMBERS = "CrewMemberBin"
|
CREWMEMBERS = "CrewMemberBin",
|
||||||
|
RIVENS = "RandomModBin"
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISlots {
|
export interface ISlots {
|
||||||
|
@ -8,7 +8,8 @@ import {
|
|||||||
IRecentVendorPurchaseClient,
|
IRecentVendorPurchaseClient,
|
||||||
TEquipmentKey,
|
TEquipmentKey,
|
||||||
ICrewMemberClient,
|
ICrewMemberClient,
|
||||||
IKubrowPetPrintClient
|
IKubrowPetPrintClient,
|
||||||
|
IUpgradeClient
|
||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
|
} from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
export enum PurchaseSource {
|
export enum PurchaseSource {
|
||||||
@ -80,6 +81,7 @@ export type IInventoryChanges = {
|
|||||||
RecentVendorPurchases?: IRecentVendorPurchaseClient; // < 38.5.0
|
RecentVendorPurchases?: IRecentVendorPurchaseClient; // < 38.5.0
|
||||||
CrewMembers?: ICrewMemberClient[];
|
CrewMembers?: ICrewMemberClient[];
|
||||||
KubrowPetPrints?: IKubrowPetPrintClient[];
|
KubrowPetPrints?: IKubrowPetPrintClient[];
|
||||||
|
Upgrades?: IUpgradeClient[]; // TOVERIFY
|
||||||
} & Record<
|
} & Record<
|
||||||
Exclude<
|
Exclude<
|
||||||
string,
|
string,
|
||||||
|
@ -3,3 +3,5 @@ type Entries<T, K extends keyof T = keyof T> = (K extends unknown ? [K, T[K]] :
|
|||||||
export function getEntriesUnsafe<T extends object>(object: T): Entries<T> {
|
export function getEntriesUnsafe<T extends object>(object: T): Entries<T> {
|
||||||
return Object.entries(object) as Entries<T>;
|
return Object.entries(object) as Entries<T>;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export const exhaustive = (_: never): void => {};
|
||||||
|
@ -135,5 +135,6 @@
|
|||||||
"/Lotus/Language/EntratiLab/EntratiGeneral/HumanLoidLoved",
|
"/Lotus/Language/EntratiLab/EntratiGeneral/HumanLoidLoved",
|
||||||
"ConquestSetupIntro",
|
"ConquestSetupIntro",
|
||||||
"EntratiLabConquestHardModeUnlocked",
|
"EntratiLabConquestHardModeUnlocked",
|
||||||
"/Lotus/Language/Npcs/KonzuPostNewWar"
|
"/Lotus/Language/Npcs/KonzuPostNewWar",
|
||||||
|
"/Lotus/Language/SolarisVenus/EudicoPostNewWar"
|
||||||
]
|
]
|
||||||
|
@ -16,6 +16,10 @@
|
|||||||
{
|
{
|
||||||
"ItemType": "/Lotus/Types/Keys/1999PrologueQuest/1999PrologueQuestKeyChain",
|
"ItemType": "/Lotus/Types/Keys/1999PrologueQuest/1999PrologueQuestKeyChain",
|
||||||
"ItemCount": 1
|
"ItemCount": 1
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"ItemType": "/Lotus/Types/Items/EmailItems/TennokaiEmailItem",
|
||||||
|
"ItemCount": 1
|
||||||
}
|
}
|
||||||
]
|
]
|
||||||
}
|
}
|
||||||
|
@ -457,7 +457,8 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<div id="detailedView-route" data-route="/webui/detailedView" data-title="Inventory | OpenWF WebUI">
|
<div id="detailedView-route" data-route="/webui/detailedView" data-title="Inventory | OpenWF WebUI">
|
||||||
<h3 class="mb-0"></h3>
|
<h3 id="detailedView-loading" class="mb-0" data-loc="general_loading"></h3>
|
||||||
|
<h3 id="detailedView-title" class="mb-0"></h3>
|
||||||
<p class="text-body-secondary"></p>
|
<p class="text-body-secondary"></p>
|
||||||
<div id="archonShards-card" class="card mb-3 d-none">
|
<div id="archonShards-card" class="card mb-3 d-none">
|
||||||
<h5 class="card-header" data-loc="detailedView_archonShardsLabel"></h5>
|
<h5 class="card-header" data-loc="detailedView_archonShardsLabel"></h5>
|
||||||
@ -527,8 +528,8 @@
|
|||||||
<form class="input-group mb-3" onsubmit="doAcquireMod();return false;">
|
<form class="input-group mb-3" onsubmit="doAcquireMod();return false;">
|
||||||
<input class="form-control" id="mod-count" type="number" value="1"/>
|
<input class="form-control" id="mod-count" type="number" value="1"/>
|
||||||
<input class="form-control w-50" id="mod-to-acquire" list="datalist-mods" />
|
<input class="form-control w-50" id="mod-to-acquire" list="datalist-mods" />
|
||||||
<button class="btn btn-success" onclick="window.maxed=true" type="submit" data-loc="mods_addMax"></button>
|
|
||||||
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
<button class="btn btn-primary" type="submit" data-loc="general_addButton"></button>
|
||||||
|
<button class="btn btn-success" onclick="window.maxed=true" data-loc="mods_addMax"></button>
|
||||||
</form>
|
</form>
|
||||||
<table class="table table-hover w-100">
|
<table class="table table-hover w-100">
|
||||||
<tbody id="mods-list"></tbody>
|
<tbody id="mods-list"></tbody>
|
||||||
@ -803,21 +804,21 @@
|
|||||||
<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">
|
<div class="input-group">
|
||||||
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" max="65535" data-default="-1" />
|
<input class="form-control" id="spoofMasteryRank" type="number" min="-1" max="65535" data-default="-1" />
|
||||||
<button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
|
<button class="btn btn-secondary" type="submit" data-loc="cheats_save"></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<form class="form-group mt-2" onsubmit="doSaveConfigInt('relicRewardItemCountMultiplier'); return false;">
|
<form class="form-group mt-2" onsubmit="doSaveConfigInt('relicRewardItemCountMultiplier'); return false;">
|
||||||
<label class="form-label" for="relicRewardItemCountMultiplier" data-loc="cheats_relicRewardItemCountMultiplier"></label>
|
<label class="form-label" for="relicRewardItemCountMultiplier" data-loc="cheats_relicRewardItemCountMultiplier"></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input class="form-control" id="relicRewardItemCountMultiplier" type="number" min="1" max="1000000" data-default="1" />
|
<input class="form-control" id="relicRewardItemCountMultiplier" type="number" min="1" max="1000000" data-default="1" />
|
||||||
<button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
|
<button class="btn btn-secondary" type="submit" data-loc="cheats_save"></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<form class="form-group mt-2" onsubmit="doSaveConfigInt('nightwaveStandingMultiplier'); return false;">
|
<form class="form-group mt-2" onsubmit="doSaveConfigInt('nightwaveStandingMultiplier'); return false;">
|
||||||
<label class="form-label" for="nightwaveStandingMultiplier" data-loc="cheats_nightwaveStandingMultiplier"></label>
|
<label class="form-label" for="nightwaveStandingMultiplier" data-loc="cheats_nightwaveStandingMultiplier"></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input class="form-control" id="nightwaveStandingMultiplier" type="number" min="1" max="1000000" data-default="1" />
|
<input class="form-control" id="nightwaveStandingMultiplier" type="number" min="1" max="1000000" data-default="1" />
|
||||||
<button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
|
<button class="btn btn-secondary" type="submit" data-loc="cheats_save"></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
@ -830,6 +831,7 @@
|
|||||||
<div class="card-body">
|
<div class="card-body">
|
||||||
<div class="mb-2 d-flex flex-wrap gap-2">
|
<div class="mb-2 d-flex flex-wrap gap-2">
|
||||||
<button class="btn btn-primary" onclick="debounce(doUnlockAllMissions);" data-loc="cheats_unlockAllMissions"></button>
|
<button class="btn btn-primary" onclick="debounce(doUnlockAllMissions);" data-loc="cheats_unlockAllMissions"></button>
|
||||||
|
<button class="btn btn-primary" onclick="debounce(markAllAsRead);" data-loc="cheats_markAllAsRead"></button>
|
||||||
<button class="btn btn-primary" onclick="doUnlockAllFocusSchools();" data-loc="cheats_unlockAllFocusSchools"></button>
|
<button class="btn btn-primary" onclick="doUnlockAllFocusSchools();" data-loc="cheats_unlockAllFocusSchools"></button>
|
||||||
<button class="btn btn-primary" onclick="doHelminthUnlockAll();" data-loc="cheats_helminthUnlockAll"></button>
|
<button class="btn btn-primary" onclick="doHelminthUnlockAll();" data-loc="cheats_helminthUnlockAll"></button>
|
||||||
<button class="btn btn-primary" onclick="debounce(addMissingHelminthRecipes);" data-loc="cheats_addMissingSubsumedAbilities"></button>
|
<button class="btn btn-primary" onclick="debounce(addMissingHelminthRecipes);" data-loc="cheats_addMissingSubsumedAbilities"></button>
|
||||||
@ -942,14 +944,14 @@
|
|||||||
<label class="form-label" for="worldState.circuitGameModes" data-loc="worldState_theCircuitOverride"></label>
|
<label class="form-label" for="worldState.circuitGameModes" data-loc="worldState_theCircuitOverride"></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="worldState.circuitGameModes" type="text" class="form-control tags-input" list="datalist-circuitGameModes" />
|
<input id="worldState.circuitGameModes" type="text" class="form-control tags-input" list="datalist-circuitGameModes" />
|
||||||
<button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
|
<button class="btn btn-secondary" type="submit" data-loc="cheats_save"></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
<form class="form-group mt-2" onsubmit="doSaveConfigFloat('worldState.darvoStockMultiplier'); return false;">
|
<form class="form-group mt-2" onsubmit="doSaveConfigFloat('worldState.darvoStockMultiplier'); return false;">
|
||||||
<label class="form-label" for="worldState.darvoStockMultiplier" data-loc="worldState_darvoStockMultiplier"></label>
|
<label class="form-label" for="worldState.darvoStockMultiplier" data-loc="worldState_darvoStockMultiplier"></label>
|
||||||
<div class="input-group">
|
<div class="input-group">
|
||||||
<input id="worldState.darvoStockMultiplier" class="form-control" type="number" step="0.01" data-default="1" />
|
<input id="worldState.darvoStockMultiplier" class="form-control" type="number" step="0.01" data-default="1" />
|
||||||
<button class="btn btn-primary" type="submit" data-loc="cheats_save"></button>
|
<button class="btn btn-secondary" type="submit" data-loc="cheats_save"></button>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</div>
|
</div>
|
||||||
|
@ -273,6 +273,8 @@ function fetchItemList() {
|
|||||||
window.itemListPromise = new Promise(resolve => {
|
window.itemListPromise = new Promise(resolve => {
|
||||||
const req = $.get("/custom/getItemLists?lang=" + window.lang);
|
const req = $.get("/custom/getItemLists?lang=" + window.lang);
|
||||||
req.done(async data => {
|
req.done(async data => {
|
||||||
|
window.allQuestKeys = data.QuestKeys;
|
||||||
|
|
||||||
await dictPromise;
|
await dictPromise;
|
||||||
|
|
||||||
document.querySelectorAll('[id^="datalist-"]').forEach(datalist => {
|
document.querySelectorAll('[id^="datalist-"]').forEach(datalist => {
|
||||||
@ -879,6 +881,14 @@ function updateInventory() {
|
|||||||
|
|
||||||
// Populate quests route
|
// Populate quests route
|
||||||
document.getElementById("QuestKeys-list").innerHTML = "";
|
document.getElementById("QuestKeys-list").innerHTML = "";
|
||||||
|
window.allQuestKeys.forEach(questKey => {
|
||||||
|
if (!data.QuestKeys.some(x => x.ItemType == questKey.uniqueName)) {
|
||||||
|
const datalist = document.getElementById("datalist-QuestKeys");
|
||||||
|
if (!datalist.querySelector(`option[data-key="${questKey.uniqueName}"]`)) {
|
||||||
|
readdQuestKey(itemMap, questKey.uniqueName);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
data.QuestKeys.forEach(item => {
|
data.QuestKeys.forEach(item => {
|
||||||
const tr = document.createElement("tr");
|
const tr = document.createElement("tr");
|
||||||
tr.setAttribute("data-item-type", item.ItemType);
|
tr.setAttribute("data-item-type", item.ItemType);
|
||||||
@ -972,10 +982,7 @@ function updateInventory() {
|
|||||||
a.href = "#";
|
a.href = "#";
|
||||||
a.onclick = function (event) {
|
a.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
const option = document.createElement("option");
|
readdQuestKey(itemMap, item.ItemType);
|
||||||
option.setAttribute("data-key", item.ItemType);
|
|
||||||
option.value = itemMap[item.ItemType]?.name ?? item.ItemType;
|
|
||||||
document.getElementById("datalist-QuestKeys").appendChild(option);
|
|
||||||
doQuestUpdate("deleteKey", item.ItemType);
|
doQuestUpdate("deleteKey", item.ItemType);
|
||||||
};
|
};
|
||||||
a.title = loc("code_remove");
|
a.title = loc("code_remove");
|
||||||
@ -1166,14 +1173,15 @@ function updateInventory() {
|
|||||||
const item = data[category].find(x => x.ItemId.$oid == oid);
|
const item = data[category].find(x => x.ItemId.$oid == oid);
|
||||||
|
|
||||||
if (item) {
|
if (item) {
|
||||||
|
document.getElementById("detailedView-loading").classList.add("d-none");
|
||||||
|
|
||||||
if (item.ItemName) {
|
if (item.ItemName) {
|
||||||
$("#detailedView-route h3").text(item.ItemName);
|
$("#detailedView-title").text(item.ItemName);
|
||||||
$("#detailedView-route .text-body-secondary").text(
|
$("#detailedView-route .text-body-secondary").text(
|
||||||
itemMap[item.ItemType]?.name ?? item.ItemType
|
itemMap[item.ItemType]?.name ?? item.ItemType
|
||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
$("#detailedView-route h3").text(itemMap[item.ItemType]?.name ?? item.ItemType);
|
$("#detailedView-title").text(itemMap[item.ItemType]?.name ?? item.ItemType);
|
||||||
$("#detailedView-route .text-body-secondary").text("");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (category == "Suits") {
|
if (category == "Suits") {
|
||||||
@ -1954,6 +1962,19 @@ for (const id of uiConfigs) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
document.querySelectorAll(".config-form .input-group").forEach(grp => {
|
||||||
|
const input = grp.querySelector("input");
|
||||||
|
const btn = grp.querySelector("button");
|
||||||
|
input.oninput = input.onchange = function () {
|
||||||
|
btn.classList.remove("btn-secondary");
|
||||||
|
btn.classList.add("btn-primary");
|
||||||
|
};
|
||||||
|
btn.onclick = function () {
|
||||||
|
btn.classList.remove("btn-primary");
|
||||||
|
btn.classList.add("btn-secondary");
|
||||||
|
};
|
||||||
|
});
|
||||||
|
|
||||||
function doSaveConfigInt(id) {
|
function doSaveConfigInt(id) {
|
||||||
$.post({
|
$.post({
|
||||||
url: "/custom/setConfig?" + window.authz + "&wsid=" + wsid,
|
url: "/custom/setConfig?" + window.authz + "&wsid=" + wsid,
|
||||||
@ -2171,7 +2192,9 @@ function doAddMissingMaxRankMods() {
|
|||||||
// DetailedView Route
|
// DetailedView Route
|
||||||
|
|
||||||
single.getRoute("#detailedView-route").on("beforeload", function () {
|
single.getRoute("#detailedView-route").on("beforeload", function () {
|
||||||
this.element.querySelector("h3").textContent = "Loading...";
|
document.getElementById("detailedView-loading").classList.remove("d-none");
|
||||||
|
document.getElementById("detailedView-title").textContent = "";
|
||||||
|
document.querySelector("#detailedView-route .text-body-secondary").textContent = "";
|
||||||
document.getElementById("archonShards-card").classList.add("d-none");
|
document.getElementById("archonShards-card").classList.add("d-none");
|
||||||
document.getElementById("valenceBonus-card").classList.add("d-none");
|
document.getElementById("valenceBonus-card").classList.add("d-none");
|
||||||
if (window.didInitialInventoryUpdate) {
|
if (window.didInitialInventoryUpdate) {
|
||||||
@ -2254,6 +2277,13 @@ function doAddCurrency(currency) {
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
function readdQuestKey(itemMap, itemType) {
|
||||||
|
const option = document.createElement("option");
|
||||||
|
option.setAttribute("data-key", itemType);
|
||||||
|
option.value = itemMap[itemType]?.name ?? itemType;
|
||||||
|
document.getElementById("datalist-QuestKeys").appendChild(option);
|
||||||
|
}
|
||||||
|
|
||||||
function doQuestUpdate(operation, itemType) {
|
function doQuestUpdate(operation, itemType) {
|
||||||
revalidateAuthz().then(() => {
|
revalidateAuthz().then(() => {
|
||||||
$.post({
|
$.post({
|
||||||
@ -2764,3 +2794,16 @@ document.querySelectorAll("#sidebar .nav-link").forEach(function (elm) {
|
|||||||
window.scrollTo(0, 0);
|
window.scrollTo(0, 0);
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
|
async function markAllAsRead() {
|
||||||
|
await revalidateAuthz();
|
||||||
|
const { Inbox } = await fetch("/api/inbox.php?" + window.authz).then(x => x.json());
|
||||||
|
let any = false;
|
||||||
|
for (const msg of Inbox) {
|
||||||
|
if (!msg.r) {
|
||||||
|
await fetch("/api/inbox.php?" + window.authz + "&messageId=" + msg.messageId.$oid);
|
||||||
|
any = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
toast(loc(any ? "code_succRelog" : "code_nothingToDo"));
|
||||||
|
}
|
||||||
|
@ -4,6 +4,7 @@ dict = {
|
|||||||
general_addButton: `Hinzufügen`,
|
general_addButton: `Hinzufügen`,
|
||||||
general_setButton: `[UNTRANSLATED] Set`,
|
general_setButton: `[UNTRANSLATED] Set`,
|
||||||
general_bulkActions: `Massenaktionen`,
|
general_bulkActions: `Massenaktionen`,
|
||||||
|
general_loading: `[UNTRANSLATED] Loading...`,
|
||||||
|
|
||||||
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
||||||
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
|
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
|
||||||
@ -44,6 +45,8 @@ dict = {
|
|||||||
code_focusUnlocked: `|COUNT| neue Fokus-Schulen freigeschaltet! Ein Inventar-Update wird benötigt, damit die Änderungen im Spiel sichtbar werden. Die Sternenkarte zu besuchen, sollte der einfachste Weg sein, dies auszulösen.`,
|
code_focusUnlocked: `|COUNT| neue Fokus-Schulen freigeschaltet! Ein Inventar-Update wird benötigt, damit die Änderungen im Spiel sichtbar werden. Die Sternenkarte zu besuchen, sollte der einfachste Weg sein, dies auszulösen.`,
|
||||||
code_addModsConfirm: `Bist du sicher, dass du |COUNT| Mods zu deinem Account hinzufügen möchtest?`,
|
code_addModsConfirm: `Bist du sicher, dass du |COUNT| Mods zu deinem Account hinzufügen möchtest?`,
|
||||||
code_succImport: `Erfolgreich importiert.`,
|
code_succImport: `Erfolgreich importiert.`,
|
||||||
|
code_succRelog: `[UNTRANSLATED] Done. Please note that you'll need to relog to see a difference in-game.`,
|
||||||
|
code_nothingToDo: `[UNTRANSLATED] Done. There was nothing to do.`,
|
||||||
code_gild: `Veredeln`,
|
code_gild: `Veredeln`,
|
||||||
code_moa: `Moa`,
|
code_moa: `Moa`,
|
||||||
code_zanuka: `Jagdhund`,
|
code_zanuka: `Jagdhund`,
|
||||||
@ -199,6 +202,7 @@ dict = {
|
|||||||
cheats_changeSupportedSyndicate: `Unterstütztes Syndikat`,
|
cheats_changeSupportedSyndicate: `Unterstütztes Syndikat`,
|
||||||
cheats_changeButton: `Ändern`,
|
cheats_changeButton: `Ändern`,
|
||||||
cheats_none: `Keines`,
|
cheats_none: `Keines`,
|
||||||
|
cheats_markAllAsRead: `[UNTRANSLATED] Mark Inbox As Read`,
|
||||||
|
|
||||||
worldState: `[UNTRANSLATED] World State`,
|
worldState: `[UNTRANSLATED] World State`,
|
||||||
worldState_creditBoost: `[UNTRANSLATED] Credit Boost`,
|
worldState_creditBoost: `[UNTRANSLATED] Credit Boost`,
|
||||||
|
@ -3,6 +3,7 @@ dict = {
|
|||||||
general_addButton: `Add`,
|
general_addButton: `Add`,
|
||||||
general_setButton: `Set`,
|
general_setButton: `Set`,
|
||||||
general_bulkActions: `Bulk Actions`,
|
general_bulkActions: `Bulk Actions`,
|
||||||
|
general_loading: `Loading...`,
|
||||||
|
|
||||||
code_loginFail: `Login failed. Double-check the email and password.`,
|
code_loginFail: `Login failed. Double-check the email and password.`,
|
||||||
code_regFail: `Registration failed. Account already exists?`,
|
code_regFail: `Registration failed. Account already exists?`,
|
||||||
@ -43,6 +44,8 @@ dict = {
|
|||||||
code_focusUnlocked: `Unlocked |COUNT| new focus schools! An inventory update will be needed for the changes to be reflected in-game. Visiting the navigation should be the easiest way to trigger that.`,
|
code_focusUnlocked: `Unlocked |COUNT| new focus schools! An inventory update will be needed for the changes to be reflected in-game. Visiting the navigation should be the easiest way to trigger that.`,
|
||||||
code_addModsConfirm: `Are you sure you want to add |COUNT| mods to your account?`,
|
code_addModsConfirm: `Are you sure you want to add |COUNT| mods to your account?`,
|
||||||
code_succImport: `Successfully imported.`,
|
code_succImport: `Successfully imported.`,
|
||||||
|
code_succRelog: `Done. Please note that you'll need to relog to see a difference in-game.`,
|
||||||
|
code_nothingToDo: `Done. There was nothing to do.`,
|
||||||
code_gild: `Gild`,
|
code_gild: `Gild`,
|
||||||
code_moa: `Moa`,
|
code_moa: `Moa`,
|
||||||
code_zanuka: `Hound`,
|
code_zanuka: `Hound`,
|
||||||
@ -198,6 +201,7 @@ dict = {
|
|||||||
cheats_changeSupportedSyndicate: `Supported syndicate`,
|
cheats_changeSupportedSyndicate: `Supported syndicate`,
|
||||||
cheats_changeButton: `Change`,
|
cheats_changeButton: `Change`,
|
||||||
cheats_none: `None`,
|
cheats_none: `None`,
|
||||||
|
cheats_markAllAsRead: `Mark Inbox As Read`,
|
||||||
|
|
||||||
worldState: `World State`,
|
worldState: `World State`,
|
||||||
worldState_creditBoost: `Credit Boost`,
|
worldState_creditBoost: `Credit Boost`,
|
||||||
|
@ -4,6 +4,7 @@ dict = {
|
|||||||
general_addButton: `Agregar`,
|
general_addButton: `Agregar`,
|
||||||
general_setButton: `Establecer`,
|
general_setButton: `Establecer`,
|
||||||
general_bulkActions: `Acciones masivas`,
|
general_bulkActions: `Acciones masivas`,
|
||||||
|
general_loading: `[UNTRANSLATED] Loading...`,
|
||||||
|
|
||||||
code_loginFail: `Error al iniciar sesión. Verifica el correo electrónico y la contraseña.`,
|
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_regFail: `Error al registrar la cuenta. ¿Ya existe una cuenta con este correo?`,
|
||||||
@ -44,6 +45,8 @@ dict = {
|
|||||||
code_focusUnlocked: `¡Desbloqueadas |COUNT| nuevas escuelas de enfoque! Se necesita una actualización del inventario para reflejar los cambios en el juego. Visitar la navegación debería ser la forma más sencilla de activarlo.`,
|
code_focusUnlocked: `¡Desbloqueadas |COUNT| nuevas escuelas de enfoque! Se necesita una actualización del inventario para reflejar los cambios en el juego. Visitar la navegación debería ser la forma más sencilla de activarlo.`,
|
||||||
code_addModsConfirm: `¿Estás seguro de que deseas agregar |COUNT| modificadores a tu cuenta?`,
|
code_addModsConfirm: `¿Estás seguro de que deseas agregar |COUNT| modificadores a tu cuenta?`,
|
||||||
code_succImport: `Importación exitosa.`,
|
code_succImport: `Importación exitosa.`,
|
||||||
|
code_succRelog: `[UNTRANSLATED] Done. Please note that you'll need to relog to see a difference in-game.`,
|
||||||
|
code_nothingToDo: `[UNTRANSLATED] Done. There was nothing to do.`,
|
||||||
code_gild: `Refinar`,
|
code_gild: `Refinar`,
|
||||||
code_moa: `Moa`,
|
code_moa: `Moa`,
|
||||||
code_zanuka: `Sabueso`,
|
code_zanuka: `Sabueso`,
|
||||||
@ -199,6 +202,7 @@ dict = {
|
|||||||
cheats_changeSupportedSyndicate: `Sindicatos disponibles`,
|
cheats_changeSupportedSyndicate: `Sindicatos disponibles`,
|
||||||
cheats_changeButton: `Cambiar`,
|
cheats_changeButton: `Cambiar`,
|
||||||
cheats_none: `Ninguno`,
|
cheats_none: `Ninguno`,
|
||||||
|
cheats_markAllAsRead: `[UNTRANSLATED] Mark Inbox As Read`,
|
||||||
|
|
||||||
worldState: `Estado del mundo`,
|
worldState: `Estado del mundo`,
|
||||||
worldState_creditBoost: `Potenciador de Créditos`,
|
worldState_creditBoost: `Potenciador de Créditos`,
|
||||||
|
@ -4,6 +4,7 @@ dict = {
|
|||||||
general_addButton: `Ajouter`,
|
general_addButton: `Ajouter`,
|
||||||
general_setButton: `[UNTRANSLATED] Set`,
|
general_setButton: `[UNTRANSLATED] Set`,
|
||||||
general_bulkActions: `Action groupée`,
|
general_bulkActions: `Action groupée`,
|
||||||
|
general_loading: `[UNTRANSLATED] Loading...`,
|
||||||
|
|
||||||
code_loginFail: `Connexion échouée. Vérifiez le mot de passe.`,
|
code_loginFail: `Connexion échouée. Vérifiez le mot de passe.`,
|
||||||
code_regFail: `Enregistrement impossible. Compte existant?`,
|
code_regFail: `Enregistrement impossible. Compte existant?`,
|
||||||
@ -44,6 +45,8 @@ dict = {
|
|||||||
code_focusUnlocked: `|COUNT| écoles de Focus déverrouillées ! Synchronisation de l'inventaire nécessaire.`,
|
code_focusUnlocked: `|COUNT| écoles de Focus déverrouillées ! Synchronisation de l'inventaire nécessaire.`,
|
||||||
code_addModsConfirm: `Ajouter |COUNT| mods à l'inventaire ?`,
|
code_addModsConfirm: `Ajouter |COUNT| mods à l'inventaire ?`,
|
||||||
code_succImport: `Importé.`,
|
code_succImport: `Importé.`,
|
||||||
|
code_succRelog: `[UNTRANSLATED] Done. Please note that you'll need to relog to see a difference in-game.`,
|
||||||
|
code_nothingToDo: `[UNTRANSLATED] Done. There was nothing to do.`,
|
||||||
code_gild: `Polir`,
|
code_gild: `Polir`,
|
||||||
code_moa: `Moa`,
|
code_moa: `Moa`,
|
||||||
code_zanuka: `Molosse`,
|
code_zanuka: `Molosse`,
|
||||||
@ -199,6 +202,7 @@ dict = {
|
|||||||
cheats_changeSupportedSyndicate: `Allégeance`,
|
cheats_changeSupportedSyndicate: `Allégeance`,
|
||||||
cheats_changeButton: `Changer`,
|
cheats_changeButton: `Changer`,
|
||||||
cheats_none: `Aucun`,
|
cheats_none: `Aucun`,
|
||||||
|
cheats_markAllAsRead: `[UNTRANSLATED] Mark Inbox As Read`,
|
||||||
|
|
||||||
worldState: `[UNTRANSLATED] World State`,
|
worldState: `[UNTRANSLATED] World State`,
|
||||||
worldState_creditBoost: `[UNTRANSLATED] Credit Boost`,
|
worldState_creditBoost: `[UNTRANSLATED] Credit Boost`,
|
||||||
|
@ -4,6 +4,7 @@ dict = {
|
|||||||
general_addButton: `Добавить`,
|
general_addButton: `Добавить`,
|
||||||
general_setButton: `Установить`,
|
general_setButton: `Установить`,
|
||||||
general_bulkActions: `Массовые действия`,
|
general_bulkActions: `Массовые действия`,
|
||||||
|
general_loading: `[UNTRANSLATED] Loading...`,
|
||||||
|
|
||||||
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
code_loginFail: `[UNTRANSLATED] Login failed. Double-check the email and password.`,
|
||||||
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
|
code_regFail: `[UNTRANSLATED] Registration failed. Account already exists?`,
|
||||||
@ -44,6 +45,8 @@ dict = {
|
|||||||
code_focusUnlocked: `Разблокировано |COUNT| новых школ фокуса! Для отображения изменений в игре потребуется обновление инвентаря. Посещение навигации — самый простой способ этого добиться.`,
|
code_focusUnlocked: `Разблокировано |COUNT| новых школ фокуса! Для отображения изменений в игре потребуется обновление инвентаря. Посещение навигации — самый простой способ этого добиться.`,
|
||||||
code_addModsConfirm: `Вы уверены, что хотите добавить |COUNT| модов на ваш аккаунт?`,
|
code_addModsConfirm: `Вы уверены, что хотите добавить |COUNT| модов на ваш аккаунт?`,
|
||||||
code_succImport: `Успешно импортировано.`,
|
code_succImport: `Успешно импортировано.`,
|
||||||
|
code_succRelog: `[UNTRANSLATED] Done. Please note that you'll need to relog to see a difference in-game.`,
|
||||||
|
code_nothingToDo: `[UNTRANSLATED] Done. There was nothing to do.`,
|
||||||
code_gild: `Улучшить`,
|
code_gild: `Улучшить`,
|
||||||
code_moa: `МОА`,
|
code_moa: `МОА`,
|
||||||
code_zanuka: `Гончая`,
|
code_zanuka: `Гончая`,
|
||||||
@ -199,6 +202,7 @@ dict = {
|
|||||||
cheats_changeSupportedSyndicate: `Поддерживаемый синдикат`,
|
cheats_changeSupportedSyndicate: `Поддерживаемый синдикат`,
|
||||||
cheats_changeButton: `Изменить`,
|
cheats_changeButton: `Изменить`,
|
||||||
cheats_none: `Отсутствует`,
|
cheats_none: `Отсутствует`,
|
||||||
|
cheats_markAllAsRead: `[UNTRANSLATED] Mark Inbox As Read`,
|
||||||
|
|
||||||
worldState: `[UNTRANSLATED] World State`,
|
worldState: `[UNTRANSLATED] World State`,
|
||||||
worldState_creditBoost: `[UNTRANSLATED] Credit Boost`,
|
worldState_creditBoost: `[UNTRANSLATED] Credit Boost`,
|
||||||
|
@ -4,6 +4,7 @@ dict = {
|
|||||||
general_addButton: `添加`,
|
general_addButton: `添加`,
|
||||||
general_setButton: `设置`,
|
general_setButton: `设置`,
|
||||||
general_bulkActions: `批量操作`,
|
general_bulkActions: `批量操作`,
|
||||||
|
general_loading: `[UNTRANSLATED] Loading...`,
|
||||||
|
|
||||||
code_loginFail: `登录失败.请检查邮箱和密码.`,
|
code_loginFail: `登录失败.请检查邮箱和密码.`,
|
||||||
code_regFail: `注册失败.账号已存在.`,
|
code_regFail: `注册失败.账号已存在.`,
|
||||||
@ -44,6 +45,8 @@ dict = {
|
|||||||
code_focusUnlocked: `已解锁|COUNT|个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新.`,
|
code_focusUnlocked: `已解锁|COUNT|个新专精学派!需要游戏内仓库更新才能生效,您可以通过访问星图来触发仓库更新.`,
|
||||||
code_addModsConfirm: `确定要向账户添加|COUNT|张MOD吗?`,
|
code_addModsConfirm: `确定要向账户添加|COUNT|张MOD吗?`,
|
||||||
code_succImport: `导入成功。`,
|
code_succImport: `导入成功。`,
|
||||||
|
code_succRelog: `[UNTRANSLATED] Done. Please note that you'll need to relog to see a difference in-game.`,
|
||||||
|
code_nothingToDo: `[UNTRANSLATED] Done. There was nothing to do.`,
|
||||||
code_gild: `镀金`,
|
code_gild: `镀金`,
|
||||||
code_moa: `恐鸟`,
|
code_moa: `恐鸟`,
|
||||||
code_zanuka: `猎犬`,
|
code_zanuka: `猎犬`,
|
||||||
@ -199,6 +202,7 @@ dict = {
|
|||||||
cheats_changeSupportedSyndicate: `支持的集团`,
|
cheats_changeSupportedSyndicate: `支持的集团`,
|
||||||
cheats_changeButton: `更改`,
|
cheats_changeButton: `更改`,
|
||||||
cheats_none: `无`,
|
cheats_none: `无`,
|
||||||
|
cheats_markAllAsRead: `[UNTRANSLATED] Mark Inbox As Read`,
|
||||||
|
|
||||||
worldState: `世界状态配置`,
|
worldState: `世界状态配置`,
|
||||||
worldState_creditBoost: `现金加成`,
|
worldState_creditBoost: `现金加成`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user