Compare commits

..

No commits in common. "main" and "main" have entirely different histories.
main ... main

40 changed files with 714 additions and 985 deletions

View File

@ -38,7 +38,6 @@
"noKimCooldowns": false,
"instantResourceExtractorDrones": false,
"noResourceExtractorDronesDamage": false,
"skipClanKeyCrafting": false,
"noDojoRoomBuildStage": false,
"noDecoBuildStage": false,
"fastDojoRoomDestruction": false,

8
package-lock.json generated
View File

@ -18,7 +18,7 @@
"morgan": "^1.10.0",
"ncp": "^2.0.0",
"typescript": "^5.5",
"warframe-public-export-plus": "^0.5.59",
"warframe-public-export-plus": "^0.5.58",
"warframe-riven-info": "^0.1.2",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0"
@ -3789,9 +3789,9 @@
}
},
"node_modules/warframe-public-export-plus": {
"version": "0.5.59",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.59.tgz",
"integrity": "sha512-/SUCVjngVDBz6gahz7CdVLywtHLODL6O5nmNtQcxFDUwrUGnF1lETcG8/UO+WLeGxBVAy4BDPbq+9ZWlYZM4uQ=="
"version": "0.5.58",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.58.tgz",
"integrity": "sha512-2G3tKcoblUl7S3Rkk5k/qH+VGZBUmU2QjtIrEO/Bt6UlgO83s648elkNdDKOLBKXnxIsa194nVwz+ci1K86sXg=="
},
"node_modules/warframe-riven-info": {
"version": "0.1.2",

View File

@ -25,7 +25,7 @@
"morgan": "^1.10.0",
"ncp": "^2.0.0",
"typescript": "^5.5",
"warframe-public-export-plus": "^0.5.59",
"warframe-public-export-plus": "^0.5.58",
"warframe-riven-info": "^0.1.2",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0"

View File

@ -17,7 +17,7 @@ export const activateRandomModController: RequestHandler = async (req, res) => {
ItemCount: -1
}
]);
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType])!;
const rivenType = getRandomElement(rivenRawToRealWeighted[request.ItemType]);
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
const upgradeIndex =
inventory.Upgrades.push({

View File

@ -28,7 +28,7 @@ export const artifactTransmutationController: RequestHandler = async (req, res)
});
const rawRivenType = getRandomRawRivenType();
const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType])!;
const rivenType = getRandomElement(rivenRawToRealWeighted[rawRivenType]);
const fingerprint = createVeiledRivenFingerprint(ExportUpgrades[rivenType]);
const upgradeIndex =

View File

@ -133,14 +133,7 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
if (recipe.secretIngredientAction != "SIA_UNBRAND") {
InventoryChanges = {
...InventoryChanges,
...(await addItem(
inventory,
recipe.resultType,
recipe.num,
false,
undefined,
pendingRecipe.TargetFingerprint
))
...(await addItem(inventory, recipe.resultType, recipe.num, false))
};
}
await inventory.save();

View File

@ -1,14 +1,8 @@
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { Guild, GuildMember } from "@/src/models/guildModel";
import { Account } from "@/src/models/loginModel";
import {
deleteGuild,
getGuildClient,
giveClanKey,
hasGuildPermission,
removeDojoKeyItems
} from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService";
import { deleteGuild, getGuildClient, hasGuildPermission, removeDojoKeyItems } from "@/src/services/guildService";
import { addRecipes, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
import { getAccountForRequest, getAccountIdForRequest, getSuffixedName } from "@/src/services/loginService";
import { GuildPermission } from "@/src/types/guildTypes";
import { IInventoryChanges } from "@/src/types/purchaseTypes";
@ -47,7 +41,14 @@ export const confirmGuildInvitationGetController: RequestHandler = async (req, r
// Update inventory of new member
const inventory = await getInventory(account._id.toString(), "GuildId LevelKeys Recipes");
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
giveClanKey(inventory, inventoryChanges);
const recipeChanges = [
{
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
ItemCount: 1
}
];
addRecipes(inventory, recipeChanges);
combineInventoryChanges(inventoryChanges, { Recipes: recipeChanges });
await inventory.save();
const guild = (await Guild.findById(req.query.clanId as string))!;
@ -95,9 +96,14 @@ export const confirmGuildInvitationPostController: RequestHandler = async (req,
await GuildMember.deleteMany({ accountId: guildMember.accountId, status: 1 });
// Update inventory of new member
const inventory = await getInventory(guildMember.accountId.toString(), "GuildId LevelKeys Recipes");
const inventory = await getInventory(guildMember.accountId.toString(), "GuildId Recipes");
inventory.GuildId = new Types.ObjectId(req.query.clanId as string);
giveClanKey(inventory);
addRecipes(inventory, [
{
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
ItemCount: 1
}
]);
await inventory.save();
// Add join to clan log

View File

@ -2,9 +2,8 @@ import { RequestHandler } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { Guild, GuildMember } from "@/src/models/guildModel";
import { createUniqueClanName, getGuildClient, giveClanKey } from "@/src/services/guildService";
import { getInventory } from "@/src/services/inventoryService";
import { IInventoryChanges } from "@/src/types/purchaseTypes";
import { createUniqueClanName, getGuildClient } from "@/src/services/guildService";
import { addRecipes, getInventory } from "@/src/services/inventoryService";
export const createGuildController: RequestHandler = async (req, res) => {
const accountId = await getAccountIdForRequest(req);
@ -27,15 +26,26 @@ export const createGuildController: RequestHandler = async (req, res) => {
rank: 0
});
const inventory = await getInventory(accountId, "GuildId LevelKeys Recipes");
const inventory = await getInventory(accountId, "GuildId Recipes");
inventory.GuildId = guild._id;
const inventoryChanges: IInventoryChanges = {};
giveClanKey(inventory, inventoryChanges);
addRecipes(inventory, [
{
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
ItemCount: 1
}
]);
await inventory.save();
res.json({
...(await getGuildClient(guild, accountId)),
InventoryChanges: inventoryChanges
InventoryChanges: {
Recipes: [
{
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
ItemCount: 1
}
]
}
});
};

View File

@ -13,7 +13,6 @@ import { addItems, combineInventoryChanges, getInventory } from "@/src/services/
import { logger } from "@/src/utils/logger";
import { ExportFlavour, ExportGear } from "warframe-public-export-plus";
import { handleStoreItemAcquisition } from "@/src/services/purchaseService";
import { fromStoreItem, isStoreItem } from "@/src/services/itemDataService";
export const inboxController: RequestHandler = async (req, res) => {
const { deleteId, lastMessage: latestClientMessageId, messageId } = req.query;
@ -49,7 +48,7 @@ export const inboxController: RequestHandler = async (req, res) => {
await addItems(
inventory,
attachmentItems.map(attItem => ({
ItemType: isStoreItem(attItem) ? fromStoreItem(attItem) : attItem,
ItemType: attItem,
ItemCount: attItem in ExportGear ? (ExportGear[attItem].purchaseQuantity ?? 1) : 1
})),
inventoryChanges

View File

@ -18,12 +18,10 @@ import {
addMiscItems,
allDailyAffiliationKeys,
cleanupInventory,
createLibraryDailyTask,
generateRewardSeed
createLibraryDailyTask
} from "@/src/services/inventoryService";
import { logger } from "@/src/utils/logger";
import { catBreadHash } from "@/src/helpers/stringHelpers";
import { Types } from "mongoose";
export const inventoryController: RequestHandler = async (request, response) => {
const accountId = await getAccountIdForRequest(request);
@ -89,7 +87,7 @@ export const inventoryController: RequestHandler = async (request, response) =>
cleanupInventory(inventory);
inventory.NextRefill = new Date((Math.trunc(Date.now() / 86400000) + 1) * 86400000);
//await inventory.save();
await inventory.save();
}
if (
@ -98,19 +96,8 @@ export const inventoryController: RequestHandler = async (request, response) =>
new Date() >= inventory.InfestedFoundry.AbilityOverrideUnlockCooldown
) {
handleSubsumeCompletion(inventory);
//await inventory.save();
}
if (inventory.LastInventorySync) {
const lastSyncDuviriMood = Math.trunc(inventory.LastInventorySync.getTimestamp().getTime() / 7200000);
const currentDuviriMood = Math.trunc(Date.now() / 7200000);
if (lastSyncDuviriMood != currentDuviriMood) {
logger.debug(`refreshing duviri seed`);
inventory.DuviriInfo.Seed = generateRewardSeed();
}
}
inventory.LastInventorySync = new Types.ObjectId();
await inventory.save();
}
response.json(await getInventoryResponse(inventory, "xpBasedLevelCapDisabled" in request.query));
};
@ -287,7 +274,7 @@ export const getInventoryResponse = async (
}
// Omitting this field so opening the navigation resyncs the inventory which is more desirable for typical usage.
inventoryResponse.LastInventorySync = undefined;
//inventoryResponse.LastInventorySync = toOid(new Types.ObjectId());
// Set 2FA enabled so trading post can be used
inventoryResponse.HWIDProtectEnabled = true;

View File

@ -141,7 +141,7 @@ const getModularWeaponSale = (
getItemType: (parts: string[]) => string
): IModularWeaponSaleInfo => {
const rng = new CRng(day);
const parts = partTypes.map(partType => rng.randomElement(partTypeToParts[partType])!);
const parts = partTypes.map(partType => rng.randomElement(partTypeToParts[partType]));
let partsCost = 0;
for (const part of parts) {
partsCost += ExportWeapons[part].premiumPrice!;

View File

@ -2,12 +2,8 @@ import {
consumeModCharge,
encodeNemesisGuess,
getInfNodes,
getKnifeUpgrade,
getNemesisPasscode,
getNemesisPasscodeModTypes,
getWeaponsForManifest,
IKnifeResponse,
showdownNodes
IKnifeResponse
} from "@/src/helpers/nemesisHelpers";
import { getJSONfromString } from "@/src/helpers/stringHelpers";
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
@ -18,8 +14,6 @@ import { IMongoDate, IOid } from "@/src/types/commonTypes";
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
import {
IInnateDamageFingerprint,
IInventoryClient,
INemesisClient,
InventorySlot,
IUpgradeClient,
IWeaponSkinClient,
@ -105,14 +99,13 @@ export const nemesisController: RequestHandler = async (req, res) => {
encodeNemesisGuess(guess[0], result1, guess[1], result2, guess[2], result3)
);
// Increase antivirus if correct antivirus mod is installed
const response: IKnifeResponse = {};
if (result1 == 0 || result2 == 0 || result3 == 0) {
// Increase antivirus
let antivirusGain = 5;
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 response: IKnifeResponse = {};
for (const upgrade of body.knife!.AttachedUpgrades) {
switch (upgrade.ItemType) {
case "/Lotus/Upgrades/Mods/DataSpike/Potency/GainAntivirusAndSpeedOnUseMod":
@ -138,12 +131,18 @@ export const nemesisController: RequestHandler = async (req, res) => {
}
}
inventory.Nemesis!.HenchmenKilled += antivirusGain;
}
if (inventory.Nemesis!.HenchmenKilled >= 100) {
inventory.Nemesis!.HenchmenKilled = 100;
inventory.Nemesis!.InfNodes = [
{
Node: "CrewBattleNode559",
Influence: 1
}
];
inventory.Nemesis!.Weakened = true;
} else {
inventory.Nemesis!.InfNodes = getInfNodes("FC_INFESTATION", 0);
}
await inventory.save();
res.json(response);
@ -171,7 +170,18 @@ export const nemesisController: RequestHandler = async (req, res) => {
let weaponIdx = -1;
if (body.target.Faction != "FC_INFESTATION") {
const weapons = getWeaponsForManifest(body.target.manifest);
let weapons: readonly string[];
if (body.target.manifest == "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix") {
weapons = kuvaLichVersionSixWeapons;
} else if (
body.target.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour" ||
body.target.manifest == "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree"
) {
weapons = corpusVersionThreeWeapons;
} else {
throw new Error(`unknown nemesis manifest: ${body.target.manifest}`);
}
const initialWeaponIdx = new SRng(body.target.fp).randomInt(0, weapons.length - 1);
weaponIdx = initialWeaponIdx;
do {
@ -213,38 +223,6 @@ export const nemesisController: RequestHandler = async (req, res) => {
res.json({
target: inventory.toJSON().Nemesis
});
} else if ((req.query.mode as string) == "w") {
const inventory = await getInventory(
accountId,
"Nemesis LoadOutPresets CurrentLoadOutIds DataKnives Upgrades RawUpgrades"
);
//const body = getJSONfromString<INemesisWeakenRequest>(String(req.body));
inventory.Nemesis!.InfNodes = [
{
Node: showdownNodes[inventory.Nemesis!.Faction],
Influence: 1
}
];
inventory.Nemesis!.Weakened = true;
const response: IKnifeResponse & { target: INemesisClient } = {
target: inventory.toJSON<IInventoryClient>().Nemesis!
};
// Consume charge of the correct requiem mod(s)
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "DATAKNIFE"))!;
const dataknifeLoadout = loadout.DATAKNIFE.id(inventory.CurrentLoadOutIds[LoadoutIndex.DATAKNIFE].$oid);
const dataknifeConfigIndex = dataknifeLoadout?.s?.mod ?? 0;
const dataknifeUpgrades = inventory.DataKnives[0].Configs[dataknifeConfigIndex].Upgrades!;
const modTypes = getNemesisPasscodeModTypes(inventory.Nemesis!);
for (const modType of modTypes) {
const upgrade = getKnifeUpgrade(inventory, dataknifeUpgrades, modType);
consumeModCharge(response, inventory, upgrade, dataknifeUpgrades);
}
await inventory.save();
res.json(response);
} else {
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
throw new Error(`unknown nemesis mode: ${String(req.query.mode)}`);
@ -296,19 +274,48 @@ interface INemesisRequiemRequest {
guess: number; // grn/crp: 4 bits | coda: 3x 4 bits
position: number; // grn/crp: 0-2 | coda: 0
// knife field provided for coda only
knife?: IKnife;
}
// interface INemesisWeakenRequest {
// target: INemesisClient;
// knife: IKnife;
// }
interface IKnife {
knife?: {
Item: IEquipmentClient;
Skins: IWeaponSkinClient[];
ModSlot: number;
CustSlot: number;
AttachedUpgrades: IUpgradeClient[];
HiddenWhenHolstered: boolean;
};
}
const kuvaLichVersionSixWeapons = [
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
"/Lotus/Weapons/Grineer/Melee/GrnKuvaLichScythe/GrnKuvaLichScytheWeapon",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Kohm/KuvaKohm",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Ogris/KuvaOgris",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Quartakk/KuvaQuartakk",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Tonkor/KuvaTonkor",
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Brakk/KuvaBrakk",
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Kraken/KuvaKraken",
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Seer/KuvaSeer",
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Stubba/KuvaStubba",
"/Lotus/Weapons/Grineer/HeavyWeapons/GrnHeavyGrenadeLauncher",
"/Lotus/Weapons/Grineer/LongGuns/GrnKuvaLichRifle/GrnKuvaLichRifleWeapon",
"/Lotus/Weapons/Grineer/Bows/GrnBow/GrnBowWeapon",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hind/KuvaHind",
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Nukor/KuvaNukor",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hek/KuvaHekWeapon",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Zarr/KuvaZarr",
"/Lotus/Weapons/Grineer/KuvaLich/HeavyWeapons/Grattler/KuvaGrattler",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Sobek/KuvaSobek"
];
const corpusVersionThreeWeapons = [
"/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
"/Lotus/Weapons/Corpus/Pistols/CrpIgniterPistol/CrpIgniterPistol",
"/Lotus/Weapons/Corpus/Pistols/CrpBriefcaseAkimbo/CrpBriefcaseAkimboPistol",
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEPlinx/CrpBEPlinxWeapon",
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEGlaxion/CrpBEGlaxion"
];

View File

@ -1,14 +1,12 @@
import { ExportRegions, ExportWarframes } from "warframe-public-export-plus";
import { IInfNode, ITypeCount } from "@/src/types/inventoryTypes/inventoryTypes";
import { getRewardAtPercentage, SRng } from "@/src/services/rngService";
import { ExportRegions } from "warframe-public-export-plus";
import { IInfNode } from "@/src/types/inventoryTypes/inventoryTypes";
import { SRng } from "@/src/services/rngService";
import { TInventoryDatabaseDocument } from "../models/inventoryModels/inventoryModel";
import { logger } from "../utils/logger";
import { IOid } from "../types/commonTypes";
import { Types } from "mongoose";
import { addMods, generateRewardSeed } from "../services/inventoryService";
import { addMods } from "../services/inventoryService";
import { isArchwingMission } from "../services/worldStateService";
import { fromStoreItem, toStoreItem } from "../services/itemDataService";
import { createMessage } from "../services/inboxService";
export const getInfNodes = (faction: string, rank: number): IInfNode[] => {
const infNodes = [];
@ -40,59 +38,17 @@ const systemIndexes: Record<string, number[]> = {
FC_INFESTATION: [23]
};
export const showdownNodes: Record<string, string> = {
FC_GRINEER: "CrewBattleNode557",
FC_CORPUS: "CrewBattleNode558",
FC_INFESTATION: "CrewBattleNode559"
};
// Get a parazon 'passcode' based on the nemesis fingerprint so it's always the same for the same nemesis.
export const getNemesisPasscode = (nemesis: { fp: bigint; Faction: string }): number[] => {
const rng = new SRng(nemesis.fp);
const choices = [0, 1, 2, 3, 5, 6, 7];
let choiceIndex = rng.randomInt(0, choices.length - 1);
const passcode = [choices[choiceIndex]];
const passcode = [rng.randomInt(0, 7)];
if (nemesis.Faction != "FC_INFESTATION") {
choices.splice(choiceIndex, 1);
choiceIndex = rng.randomInt(0, choices.length - 1);
passcode.push(choices[choiceIndex]);
choices.splice(choiceIndex, 1);
choiceIndex = rng.randomInt(0, choices.length - 1);
passcode.push(choices[choiceIndex]);
passcode.push(rng.randomInt(0, 7));
passcode.push(rng.randomInt(0, 7));
}
return passcode;
};
const reqiuemMods: readonly string[] = [
"/Lotus/Upgrades/Mods/Immortal/ImmortalOneMod",
"/Lotus/Upgrades/Mods/Immortal/ImmortalTwoMod",
"/Lotus/Upgrades/Mods/Immortal/ImmortalThreeMod",
"/Lotus/Upgrades/Mods/Immortal/ImmortalFourMod",
"/Lotus/Upgrades/Mods/Immortal/ImmortalFiveMod",
"/Lotus/Upgrades/Mods/Immortal/ImmortalSixMod",
"/Lotus/Upgrades/Mods/Immortal/ImmortalSevenMod",
"/Lotus/Upgrades/Mods/Immortal/ImmortalEightMod"
];
const antivirusMods: readonly string[] = [
"/Lotus/Upgrades/Mods/Immortal/AntivirusOneMod",
"/Lotus/Upgrades/Mods/Immortal/AntivirusTwoMod",
"/Lotus/Upgrades/Mods/Immortal/AntivirusThreeMod",
"/Lotus/Upgrades/Mods/Immortal/AntivirusFourMod",
"/Lotus/Upgrades/Mods/Immortal/AntivirusFiveMod",
"/Lotus/Upgrades/Mods/Immortal/AntivirusSixMod",
"/Lotus/Upgrades/Mods/Immortal/AntivirusSevenMod",
"/Lotus/Upgrades/Mods/Immortal/AntivirusEightMod"
];
export const getNemesisPasscodeModTypes = (nemesis: { fp: bigint; Faction: string }): string[] => {
const passcode = getNemesisPasscode(nemesis);
return nemesis.Faction == "FC_INFESTATION"
? passcode.map(i => antivirusMods[i])
: passcode.map(i => reqiuemMods[i]);
};
export const encodeNemesisGuess = (
symbol1: number,
result1: number,
@ -123,31 +79,6 @@ export interface IKnifeResponse {
HasKnife?: boolean;
}
export const getKnifeUpgrade = (
inventory: TInventoryDatabaseDocument,
dataknifeUpgrades: string[],
type: string
): { ItemId: IOid; ItemType: string } => {
if (dataknifeUpgrades.indexOf(type) != -1) {
return {
ItemId: { $oid: "000000000000000000000000" },
ItemType: type
};
}
for (const upgradeId of dataknifeUpgrades) {
if (upgradeId.length == 24) {
const upgrade = inventory.Upgrades.id(upgradeId);
if (upgrade && upgrade.ItemType == type) {
return {
ItemId: { $oid: upgradeId },
ItemType: type
};
}
}
}
throw new Error(`${type} does not seem to be installed on parazon?!`);
};
export const consumeModCharge = (
response: IKnifeResponse,
inventory: TInventoryDatabaseDocument,
@ -198,181 +129,3 @@ export const consumeModCharge = (
response.UpgradeNew.push(true);
}
};
const kuvaLichVersionSixWeapons = [
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Drakgoon/KuvaDrakgoon",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Karak/KuvaKarak",
"/Lotus/Weapons/Grineer/Melee/GrnKuvaLichScythe/GrnKuvaLichScytheWeapon",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Kohm/KuvaKohm",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Ogris/KuvaOgris",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Quartakk/KuvaQuartakk",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Tonkor/KuvaTonkor",
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Brakk/KuvaBrakk",
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Kraken/KuvaKraken",
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Seer/KuvaSeer",
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Stubba/KuvaStubba",
"/Lotus/Weapons/Grineer/HeavyWeapons/GrnHeavyGrenadeLauncher",
"/Lotus/Weapons/Grineer/LongGuns/GrnKuvaLichRifle/GrnKuvaLichRifleWeapon",
"/Lotus/Weapons/Grineer/Bows/GrnBow/GrnBowWeapon",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hind/KuvaHind",
"/Lotus/Weapons/Grineer/KuvaLich/Secondaries/Nukor/KuvaNukor",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Hek/KuvaHekWeapon",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Zarr/KuvaZarr",
"/Lotus/Weapons/Grineer/KuvaLich/HeavyWeapons/Grattler/KuvaGrattler",
"/Lotus/Weapons/Grineer/KuvaLich/LongGuns/Sobek/KuvaSobek"
];
const corpusVersionThreeWeapons = [
"/Lotus/Weapons/Corpus/LongGuns/CrpBriefcaseLauncher/CrpBriefcaseLauncher",
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEArcaPlasmor/CrpBEArcaPlasmor",
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEFluxRifle/CrpBEFluxRifle",
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBETetra/CrpBETetra",
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBECycron/CrpBECycron",
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEDetron/CrpBEDetron",
"/Lotus/Weapons/Corpus/Pistols/CrpIgniterPistol/CrpIgniterPistol",
"/Lotus/Weapons/Corpus/Pistols/CrpBriefcaseAkimbo/CrpBriefcaseAkimboPistol",
"/Lotus/Weapons/Corpus/BoardExec/Secondary/CrpBEPlinx/CrpBEPlinxWeapon",
"/Lotus/Weapons/Corpus/BoardExec/Primary/CrpBEGlaxion/CrpBEGlaxion"
];
export const getWeaponsForManifest = (manifest: string): readonly string[] => {
switch (manifest) {
case "/Lotus/Types/Game/Nemesis/KuvaLich/KuvaLichManifestVersionSix":
return kuvaLichVersionSixWeapons;
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionThree":
case "/Lotus/Types/Enemies/Corpus/Lawyers/LawyerManifestVersionFour":
return corpusVersionThreeWeapons;
}
throw new Error(`unknown nemesis manifest: ${manifest}`);
};
export const getInnateDamageTag = (
KillingSuit: string
):
| "InnateElectricityDamage"
| "InnateFreezeDamage"
| "InnateHeatDamage"
| "InnateImpactDamage"
| "InnateMagDamage"
| "InnateRadDamage"
| "InnateToxinDamage" => {
return ExportWarframes[KillingSuit].nemesisUpgradeTag!;
};
// TODO: For -1399275245665749231n, the value should be 75306944, but we're off by 59 with 75307003.
export const getInnateDamageValue = (fp: bigint): number => {
const rng = new SRng(fp);
rng.randomFloat(); // used for the weapon index
const WeaponUpgradeValueAttenuationExponent = 2.25;
let value = Math.pow(rng.randomFloat(), WeaponUpgradeValueAttenuationExponent);
if (value >= 0.941428) {
value = 1;
}
return Math.trunc(value * 0x40000000);
};
export const getKillTokenRewardCount = (fp: bigint): number => {
const rng = new SRng(fp);
return rng.randomInt(10, 15);
};
// /Lotus/Types/Enemies/InfestedLich/InfestedLichRewardManifest
const infestedLichRotA = [
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDJRomHuman", probability: 0.046 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDJRomInfested", probability: 0.045 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDrillbitHuman", probability: 0.046 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyDrillbitInfested", probability: 0.045 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyHarddriveHuman", probability: 0.046 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyHarddriveInfested", probability: 0.045 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyPacketHuman", probability: 0.046 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyPacketInfested", probability: 0.045 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyZekeHuman", probability: 0.046 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/Plushies/PlushyZekeInfested", probability: 0.045 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandBillboardPosterA", probability: 0.045 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandBillboardPosterB", probability: 0.046 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandDespairPoster", probability: 0.045 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandGridPoster", probability: 0.046 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandHuddlePoster", probability: 0.045 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandJumpPoster", probability: 0.046 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLimoPoster", probability: 0.045 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLookingDownPosterDay", probability: 0.046 },
{
type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandLookingDownPosterNight",
probability: 0.045
},
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandSillyPoster", probability: 0.046 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandWhiteBluePoster", probability: 0.045 },
{ type: "/Lotus/StoreItems/Types/Items/ShipDecos/BoybandPosters/BoybandWhitePinkPoster", probability: 0.045 }
];
const infestedLichRotB = [
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraA", probability: 0.072 },
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraB", probability: 0.071 },
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraC", probability: 0.072 },
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraD", probability: 0.071 },
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraE", probability: 0.072 },
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraF", probability: 0.071 },
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraG", probability: 0.071 },
{ type: "/Lotus/StoreItems/Upgrades/Skins/Effects/InfestedLichEphemeraH", probability: 0.072 },
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceDJRomHype", probability: 0.071 },
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DancePacketWindmillShuffle", probability: 0.072 },
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceHarddrivePony", probability: 0.071 },
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceDrillbitCrisscross", probability: 0.072 },
{ type: "/Lotus/StoreItems/Types/Items/Emotes/DanceZekeCanthavethis", probability: 0.071 },
{ type: "/Lotus/StoreItems/Types/Items/PhotoBooth/PhotoboothTileRJLasXStadiumBossArena", probability: 0.071 }
];
export const getInfestedLichItemRewards = (fp: bigint): string[] => {
const rng = new SRng(fp);
const rotAReward = getRewardAtPercentage(infestedLichRotA, rng.randomFloat())!.type;
rng.randomFloat(); // unused afaict
const rotBReward = getRewardAtPercentage(infestedLichRotB, rng.randomFloat())!.type;
return [rotAReward, rotBReward];
};
export const sendCodaFinishedMessage = async (
inventory: TInventoryDatabaseDocument,
fp: bigint = generateRewardSeed(),
name: string = "ZEKE_BEATWOMAN_TM.1999",
killed: boolean = true
): Promise<void> => {
const att: string[] = [];
// First vanquish/convert gives a sigil
const sigil = killed
? "/Lotus/Upgrades/Skins/Sigils/InfLichVanquishedSigil"
: "/Lotus/Upgrades/Skins/Sigils/InfLichConvertedSigil";
if (!inventory.WeaponSkins.find(x => x.ItemType == sigil)) {
att.push(toStoreItem(sigil));
}
const [rotAReward, rotBReward] = getInfestedLichItemRewards(fp);
att.push(fromStoreItem(rotAReward));
att.push(fromStoreItem(rotBReward));
let countedAtt: ITypeCount[] | undefined;
if (killed) {
countedAtt = [
{
ItemType: "/Lotus/Types/Items/MiscItems/CodaWeaponBucks",
ItemCount: getKillTokenRewardCount(fp)
}
];
}
await createMessage(inventory.accountOwnerId, [
{
sndr: "/Lotus/Language/Bosses/Ordis",
msg: "/Lotus/Language/Inbox/VanquishBandMsgBody",
arg: [
{
Key: "LICH_NAME",
Tag: name
}
],
att: att,
countedAtt: countedAtt,
sub: "/Lotus/Language/Inbox/VanquishBandMsgTitle",
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
highPriority: true
}
]);
};

View File

@ -31,7 +31,7 @@ export interface IFingerprintStat {
}
export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFingerprint => {
const challenge = getRandomElement(meta.availableChallenges!)!;
const challenge = getRandomElement(meta.availableChallenges!);
const fingerprintChallenge: IRivenChallenge = {
Type: challenge.fullName,
Progress: 0,
@ -54,11 +54,11 @@ export const createVeiledRivenFingerprint = (meta: IUpgrade): IVeiledRivenFinger
export const createUnveiledRivenFingerprint = (meta: IUpgrade): IUnveiledRivenFingerprint => {
const fingerprint: IUnveiledRivenFingerprint = {
compat: getRandomElement(meta.compatibleItems!)!,
compat: getRandomElement(meta.compatibleItems!),
lim: 0,
lvl: 0,
lvlReq: getRandomInt(8, 16),
pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"])!,
pol: getRandomElement(["AP_ATTACK", "AP_DEFENSE", "AP_TACTIC"]),
buffs: [],
curses: []
};
@ -81,7 +81,7 @@ export const randomiseRivenStats = (meta: IUpgrade, fingerprint: IUnveiledRivenF
if (Math.random() < 0.5) {
const entry = getRandomElement(
meta.upgradeEntries!.filter(x => x.canBeCurse && !fingerprint.buffs.find(y => y.Tag == x.tag))
)!;
);
fingerprint.curses.push({ Tag: entry.tag, Value: Math.trunc(Math.random() * 0x40000000) });
}
};

View File

@ -781,25 +781,9 @@ const loreFragmentScansSchema = new Schema<ILoreFragmentScan>(
{ _id: false }
);
// const lotusCustomizationSchema = new Schema<ILotusCustomization>().add(ItemConfigSchema).add({
// Persona: String
// });
// Laxer schema for cleanupInventory
const lotusCustomizationSchema = new Schema<ILotusCustomization>(
{
Skins: [String],
pricol: colorSchema,
attcol: Schema.Types.Mixed,
sigcol: Schema.Types.Mixed,
eyecol: Schema.Types.Mixed,
facial: Schema.Types.Mixed,
cloth: Schema.Types.Mixed,
syancol: Schema.Types.Mixed,
const lotusCustomizationSchema = new Schema<ILotusCustomization>().add(ItemConfigSchema).add({
Persona: String
},
{ _id: false }
);
});
const evolutionProgressSchema = new Schema<IEvolutionProgress>(
{
@ -1055,8 +1039,6 @@ const pendingRecipeSchema = new Schema<IPendingRecipeDatabase>(
{
ItemType: String,
CompletionDate: Date,
TargetItemId: String,
TargetFingerprint: String,
LongGuns: { type: [EquipmentSchema], default: undefined },
Pistols: { type: [EquipmentSchema], default: undefined },
Melee: { type: [EquipmentSchema], default: undefined },
@ -1278,11 +1260,11 @@ const nemesisSchema = new Schema<INemesisDatabase>(
PrevOwners: Number,
SecondInCommand: Boolean,
Weakened: Boolean,
InfNodes: { type: [infNodeSchema], default: undefined },
InfNodes: [infNodeSchema],
HenchmenKilled: Number,
HintProgress: Number,
Hints: { type: [Number], default: undefined },
GuessHistory: { type: [Number], default: undefined },
Hints: [Number],
GuessHistory: [Number],
MissionCount: Number,
LastEnc: Number
},
@ -1399,7 +1381,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//How many Gift do you have left*(gift spends the trade)
GiftsRemaining: { type: Number, default: 8 },
//Curent trade info Giving or Getting items
//PendingTrades: [Schema.Types.Mixed],
PendingTrades: [Schema.Types.Mixed],
//Syndicate currently being pledged to.
SupportedSyndicate: String,
@ -1449,7 +1431,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
KubrowPetEggs: [kubrowPetEggSchema],
//Prints Cat(3 Prints)\Kubrow(2 Prints) Pets
//KubrowPetPrints: [Schema.Types.Mixed],
KubrowPetPrints: [Schema.Types.Mixed],
//Item for EquippedGear example:Scaner,LoadoutTechSummon etc
Consumables: [typeCountSchema],
@ -1495,7 +1477,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//item like DojoKey or Boss missions key
LevelKeys: [typeCountSchema],
//Active quests
//Quests: [Schema.Types.Mixed],
Quests: [Schema.Types.Mixed],
//Cosmetics like profile glyphs\Kavasa Prime Kubrow Collar\Game Theme etc
FlavourItems: [FlavourItemSchema],
@ -1534,7 +1516,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
TauntHistory: { type: [tauntSchema], default: undefined },
//noShow2FA,VisitPrimeVault etc
//WebFlags: Schema.Types.Mixed,
WebFlags: Schema.Types.Mixed,
//Id CompletedAlerts
CompletedAlerts: [String],
@ -1554,7 +1536,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//the color your clan requests like Items/Research/DojoColors/DojoColorPlainsB
ActiveDojoColorResearch: String,
//SentientSpawnChanceBoosters: Schema.Types.Mixed,
SentientSpawnChanceBoosters: Schema.Types.Mixed,
QualifyingInvasions: [invasionProgressSchema],
FactionScores: [Number],
@ -1589,10 +1571,10 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
// open location store like EidolonPlainsDiscoverable or OrbVallisCaveDiscoverable
DiscoveredMarkers: [discoveredMarkerSchema],
//Open location mission like "JobId" + "StageCompletions"
//CompletedJobs: [Schema.Types.Mixed],
CompletedJobs: [Schema.Types.Mixed],
//Game mission\ivent score example "Tag": "WaterFight", "Best": 170, "Count": 1258,
//PersonalGoalProgress: [Schema.Types.Mixed],
PersonalGoalProgress: [Schema.Types.Mixed],
//Setting interface Style
ThemeStyle: String,
@ -1622,13 +1604,13 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
LibraryActiveDailyTaskInfo: libraryDailyTaskInfoSchema,
//https://warframe.fandom.com/wiki/Invasion
//InvasionChainProgress: [Schema.Types.Mixed],
InvasionChainProgress: [Schema.Types.Mixed],
//CorpusLich or GrineerLich
NemesisAbandonedRewards: { type: [String], default: [] },
Nemesis: nemesisSchema,
NemesisHistory: { type: [nemesisSchema], default: undefined },
//LastNemesisAllySpawnTime: Schema.Types.Mixed,
NemesisHistory: [Schema.Types.Mixed],
LastNemesisAllySpawnTime: Schema.Types.Mixed,
//TradingRulesConfirmed,ShowFriendInvNotifications(Option->Social)
Settings: settingsSchema,
@ -1642,7 +1624,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
PlayerSkills: { type: playerSkillsSchema, default: {} },
//TradeBannedUntil data
//TradeBannedUntil: Schema.Types.Mixed,
TradeBannedUntil: Schema.Types.Mixed,
//https://warframe.fandom.com/wiki/Helminth
InfestedFoundry: infestedFoundrySchema,
@ -1662,24 +1644,23 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
//Unknown and system
DuviriInfo: DuviriInfoSchema,
LastInventorySync: Schema.Types.ObjectId,
Mailbox: MailboxSchema,
HandlerPoints: Number,
ChallengesFixVersion: { type: Number, default: 6 },
PlayedParkourTutorial: Boolean,
//ActiveLandscapeTraps: [Schema.Types.Mixed],
//RepVotes: [Schema.Types.Mixed],
//LeagueTickets: [Schema.Types.Mixed],
ActiveLandscapeTraps: [Schema.Types.Mixed],
RepVotes: [Schema.Types.Mixed],
LeagueTickets: [Schema.Types.Mixed],
HasContributedToDojo: Boolean,
HWIDProtectEnabled: Boolean,
LoadOutPresets: { type: Schema.Types.ObjectId, ref: "Loadout" },
CurrentLoadOutIds: [oidSchema],
RandomUpgradesIdentified: Number,
BountyScore: Number,
//ChallengeInstanceStates: [Schema.Types.Mixed],
ChallengeInstanceStates: [Schema.Types.Mixed],
RecentVendorPurchases: { type: [recentVendorPurchaseSchema], default: undefined },
//Robotics: [Schema.Types.Mixed],
//UsedDailyDeals: [Schema.Types.Mixed],
Robotics: [Schema.Types.Mixed],
UsedDailyDeals: [Schema.Types.Mixed],
CollectibleSeries: { type: [collectibleEntrySchema], default: undefined },
HasResetAccount: { type: Boolean, default: false },
@ -1760,9 +1741,6 @@ inventorySchema.set("toJSON", {
sn: inventoryDatabase.LockedWeaponGroup.sn ? toOid(inventoryDatabase.LockedWeaponGroup.sn) : undefined
};
}
if (inventoryDatabase.LastInventorySync) {
inventoryResponse.LastInventorySync = toOid(inventoryDatabase.LastInventorySync);
}
}
});

View File

@ -44,7 +44,6 @@ interface IConfig {
noKimCooldowns?: boolean;
instantResourceExtractorDrones?: boolean;
noResourceExtractorDronesDamage?: boolean;
skipClanKeyCrafting?: boolean;
noDojoRoomBuildStage?: boolean;
noDojoDecoBuildStage?: boolean;
fastDojoRoomDestruction?: boolean;

View File

@ -1,6 +1,6 @@
import { Request } from "express";
import { getAccountIdForRequest } from "@/src/services/loginService";
import { addLevelKeys, addRecipes, combineInventoryChanges, getInventory } from "@/src/services/inventoryService";
import { getInventory } from "@/src/services/inventoryService";
import { Alliance, AllianceMember, Guild, GuildAd, GuildMember, TGuildDatabaseDocument } from "@/src/models/guildModel";
import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel";
import {
@ -657,32 +657,6 @@ export const checkClanAscensionHasRequiredContributors = async (guild: TGuildDat
}
};
export const giveClanKey = (inventory: TInventoryDatabaseDocument, inventoryChanges?: IInventoryChanges): void => {
if (config.skipClanKeyCrafting) {
const levelKeyChanges = [
{
ItemType: "/Lotus/Types/Keys/DojoKey",
ItemCount: 1
}
];
addLevelKeys(inventory, levelKeyChanges);
if (inventoryChanges) {
combineInventoryChanges(inventoryChanges, { LevelKeys: levelKeyChanges });
}
} else {
const recipeChanges = [
{
ItemType: "/Lotus/Types/Keys/DojoKeyBlueprint",
ItemCount: 1
}
];
addRecipes(inventory, recipeChanges);
if (inventoryChanges) {
combineInventoryChanges(inventoryChanges, { Recipes: recipeChanges });
}
}
};
export const removeDojoKeyItems = (inventory: TInventoryDatabaseDocument): IInventoryChanges => {
const inventoryChanges: IInventoryChanges = {};

View File

@ -2,7 +2,6 @@ import { Types } from "mongoose";
import {
IEquipmentClient,
IEquipmentDatabase,
IItemConfig,
IOperatorConfigClient,
IOperatorConfigDatabase
} from "../types/inventoryTypes/commonInventoryTypes";
@ -175,20 +174,6 @@ const convertNemesis = (client: INemesisClient): INemesisDatabase => {
};
};
// Empty objects from live may have been encoded as empty arrays because of PHP.
const convertItemConfig = <T extends IItemConfig>(client: T): T => {
return {
...client,
pricol: Array.isArray(client.pricol) ? {} : client.pricol,
attcol: Array.isArray(client.attcol) ? {} : client.attcol,
sigcol: Array.isArray(client.sigcol) ? {} : client.sigcol,
eyecol: Array.isArray(client.eyecol) ? {} : client.eyecol,
facial: Array.isArray(client.facial) ? {} : client.facial,
cloth: Array.isArray(client.cloth) ? {} : client.cloth,
syancol: Array.isArray(client.syancol) ? {} : client.syancol
};
};
export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<IInventoryClient>): void => {
for (const key of equipmentKeys) {
if (client[key] !== undefined) {
@ -367,7 +352,7 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
db.PlayerSkills = client.PlayerSkills;
}
if (client.LotusCustomization !== undefined) {
db.LotusCustomization = convertItemConfig(client.LotusCustomization);
db.LotusCustomization = client.LotusCustomization;
}
if (client.CollectibleSeries !== undefined) {
db.CollectibleSeries = client.CollectibleSeries;

View File

@ -26,9 +26,7 @@ import {
Status,
IKubrowPetDetailsDatabase,
ITraits,
ICalendarProgress,
INemesisWeaponTargetFingerprint,
INemesisPetTargetFingerprint
ICalendarProgress
} from "@/src/types/inventoryTypes/inventoryTypes";
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
@ -81,7 +79,6 @@ import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from ".
import { createMessage } from "./inboxService";
import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper";
import { getWorldState } from "./worldStateService";
import { getInnateDamageTag, getInnateDamageValue } from "../helpers/nemesisHelpers";
export const createInventory = async (
accountOwnerId: Types.ObjectId,
@ -330,8 +327,7 @@ export const addItem = async (
typeName: string,
quantity: number = 1,
premiumPurchase: boolean = false,
seed?: bigint,
targetFingerprint?: string
seed?: bigint
): Promise<IInventoryChanges> => {
// Bundles are technically StoreItems but a) they don't have a normal counterpart, and b) they are used in non-StoreItem contexts, e.g. email attachments.
if (typeName in ExportBundles) {
@ -534,12 +530,6 @@ export const addItem = async (
]
});
}
if (targetFingerprint) {
const targetFingerprintObj = JSON.parse(targetFingerprint) as INemesisWeaponTargetFingerprint;
defaultOverwrites.UpgradeType = targetFingerprintObj.ItemType;
defaultOverwrites.UpgradeFingerprint = JSON.stringify(targetFingerprintObj.UpgradeFingerprint);
defaultOverwrites.ItemName = targetFingerprintObj.Name;
}
const inventoryChanges = addEquipment(inventory, weapon.productCategory, typeName, defaultOverwrites);
if (weapon.additionalItems) {
for (const item of weapon.additionalItems) {
@ -554,27 +544,6 @@ export const addItem = async (
premiumPurchase
)
};
} else if (targetFingerprint) {
// Sister's Hound
const targetFingerprintObj = JSON.parse(targetFingerprint) as INemesisPetTargetFingerprint;
const head = targetFingerprintObj.Parts[0];
const defaultOverwrites: Partial<IEquipmentDatabase> = {
ModularParts: targetFingerprintObj.Parts,
ItemName: targetFingerprintObj.Name,
Configs: applyDefaultUpgrades(inventory, ExportWeapons[head].defaultUpgrades)
};
const itemType = {
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA":
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetAPowerSuit",
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB":
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetBPowerSuit",
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC":
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetCPowerSuit"
}[head] as string;
return {
...addEquipment(inventory, "MoaPets", itemType, defaultOverwrites),
...occupySlot(inventory, InventorySlot.SENTINELS, premiumPurchase)
};
} else {
// Modular weapon parts
const miscItemChanges = [
@ -1798,7 +1767,7 @@ export const addKeyChainItems = async (
};
export const createLibraryDailyTask = (): ILibraryDailyTaskInfo => {
const enemyTypes = getRandomElement(libraryDailyTasks)!;
const enemyTypes = getRandomElement(libraryDailyTasks);
const enemyAvatar = ExportEnemies.avatars[enemyTypes[0]];
const scansRequired = getRandomInt(2, 4);
return {
@ -1847,25 +1816,6 @@ export const cleanupInventory = (inventory: TInventoryDatabaseDocument): void =>
logger.debug(`removing FreeFavorsEarned from LibrarySyndicate`);
LibrarySyndicate.FreeFavorsEarned = undefined;
}
if (inventory.LotusCustomization) {
if (
Array.isArray(inventory.LotusCustomization.attcol) ||
Array.isArray(inventory.LotusCustomization.sigcol) ||
Array.isArray(inventory.LotusCustomization.eyecol) ||
Array.isArray(inventory.LotusCustomization.facial) ||
Array.isArray(inventory.LotusCustomization.cloth) ||
Array.isArray(inventory.LotusCustomization.syancol)
) {
logger.debug(`fixing empty objects represented as empty arrays in LotusCustomization`);
inventory.LotusCustomization.attcol = {};
inventory.LotusCustomization.sigcol = {};
inventory.LotusCustomization.eyecol = {};
inventory.LotusCustomization.facial = {};
inventory.LotusCustomization.cloth = {};
inventory.LotusCustomization.syancol = {};
}
}
};
export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICalendarProgress => {
@ -1901,78 +1851,3 @@ export const getCalendarProgress = (inventory: TInventoryDatabaseDocument): ICal
return inventory.CalendarProgress;
};
export const giveNemesisWeaponRecipe = (
inventory: TInventoryDatabaseDocument,
weaponType: string,
nemesisName: string = "AGOR ROK",
weaponLoc?: string,
KillingSuit: string = "/Lotus/Powersuits/Ember/Ember",
fp: bigint = generateRewardSeed()
): void => {
if (!weaponLoc) {
weaponLoc = ExportWeapons[weaponType].name;
}
const recipeType = Object.entries(ExportRecipes).find(arr => arr[1].resultType == weaponType)![0];
addRecipes(inventory, [
{
ItemType: recipeType,
ItemCount: 1
}
]);
inventory.PendingRecipes.push({
CompletionDate: new Date(),
ItemType: recipeType,
TargetFingerprint: JSON.stringify({
ItemType: "/Lotus/Weapons/Grineer/KuvaLich/Upgrades/InnateDamageRandomMod",
UpgradeFingerprint: {
compat: weaponType,
buffs: [
{
Tag: getInnateDamageTag(KillingSuit),
Value: getInnateDamageValue(fp)
}
]
},
Name: weaponLoc + "|" + nemesisName
} satisfies INemesisWeaponTargetFingerprint)
});
};
export const giveNemesisPetRecipe = (inventory: TInventoryDatabaseDocument, nemesisName: string = "AGOR ROK"): void => {
const head = getRandomElement([
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA",
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB",
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC"
])!;
const body = getRandomElement([
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyA",
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyB",
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartBodyC"
])!;
const legs = getRandomElement([
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsA",
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsB",
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartLegsC"
])!;
const tail = getRandomElement([
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailA",
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailB",
"/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartTailC"
])!;
const recipeType = Object.entries(ExportRecipes).find(arr => arr[1].resultType == head)![0];
addRecipes(inventory, [
{
ItemType: recipeType,
ItemCount: 1
}
]);
inventory.PendingRecipes.push({
CompletionDate: new Date(),
ItemType: recipeType,
TargetFingerprint: JSON.stringify({
Parts: [head, body, legs, tail],
Name: "/Lotus/Language/Pets/ZanukaPetName|" + nemesisName
} satisfies INemesisPetTargetFingerprint)
});
};

View File

@ -17,7 +17,6 @@ import {
dict_uk,
dict_zh,
ExportArcanes,
ExportBoosters,
ExportCustoms,
ExportDrones,
ExportGear,
@ -218,30 +217,15 @@ export const convertInboxMessage = (message: IInboxMessage): IMessage => {
};
export const isStoreItem = (type: string): boolean => {
return type.startsWith("/Lotus/StoreItems/") || type in ExportBoosters;
return type.startsWith("/Lotus/StoreItems/");
};
export const toStoreItem = (type: string): string => {
if (type.startsWith("/Lotus/Types/StoreItems/Boosters/")) {
const boosterEntry = Object.entries(ExportBoosters).find(arr => arr[1].typeName == type);
if (boosterEntry) {
return boosterEntry[0];
}
throw new Error(`could not convert ${type} to a store item`);
}
return "/Lotus/StoreItems/" + type.substring("/Lotus/".length);
};
export const fromStoreItem = (type: string): string => {
if (type.startsWith("/Lotus/StoreItems/")) {
return "/Lotus/" + type.substring("/Lotus/StoreItems/".length);
}
if (type in ExportBoosters) {
return ExportBoosters[type].typeName;
}
throw new Error(`${type} is not a store item`);
};
export const getDefaultUpgrades = (parts: string[]): IDefaultUpgrade[] | undefined => {

View File

@ -77,6 +77,7 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab
const reward = rng.randomReward(randomRewards)!;
//const reward = randomRewards.find(x => x.RewardType == "RT_BOOSTER")!;
if (reward.RewardType == "RT_RANDOM_RECIPE") {
// Not very faithful implementation but roughly the same idea
const masteredItems = new Set();
for (const entry of inventory.XPInfo) {
masteredItems.add(entry.ItemType);
@ -94,15 +95,15 @@ const getRandomLoginReward = (rng: CRng, day: number, inventory: TInventoryDatab
}
const eligibleRecipes: string[] = [];
for (const [uniqueName, recipe] of Object.entries(ExportRecipes)) {
if (!recipe.excludeFromMarket && unmasteredItems.has(recipe.resultType)) {
if (unmasteredItems.has(recipe.resultType)) {
eligibleRecipes.push(uniqueName);
}
}
if (eligibleRecipes.length == 0) {
// This account has all applicable warframes and weapons already mastered (filthy cheater), need a different reward.
// This account has all warframes and weapons already mastered (filthy cheater), need a different reward.
return getRandomLoginReward(rng, day, inventory);
}
reward.StoreItemType = toStoreItem(rng.randomElement(eligibleRecipes)!);
reward.StoreItemType = toStoreItem(rng.randomElement(eligibleRecipes));
}
return {
//_id: toOid(new Types.ObjectId()),

View File

@ -35,8 +35,6 @@ import {
combineInventoryChanges,
generateRewardSeed,
getCalendarProgress,
giveNemesisPetRecipe,
giveNemesisWeaponRecipe,
updateCurrency,
updateSyndicate
} from "@/src/services/inventoryService";
@ -55,7 +53,7 @@ import kuriaMessage50 from "@/static/fixed_responses/kuriaMessages/fiftyPercent.
import kuriaMessage75 from "@/static/fixed_responses/kuriaMessages/seventyFivePercent.json";
import kuriaMessage100 from "@/static/fixed_responses/kuriaMessages/oneHundredPercent.json";
import conservationAnimals from "@/static/fixed_responses/conservationAnimals.json";
import { getInfNodes, getWeaponsForManifest, sendCodaFinishedMessage } from "@/src/helpers/nemesisHelpers";
import { getInfNodes } from "@/src/helpers/nemesisHelpers";
import { Loadout } from "../models/inventoryModels/loadoutModel";
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
import { getLiteSortie, getWorldState, idToWeek } from "./worldStateService";
@ -380,7 +378,6 @@ export const addMissionInventoryUpdates = async (
: 10)
) {
progress.Completed = true;
inventory.LibraryPersonalTarget = undefined;
}
logger.debug(`synthesis of ${scan.EnemyType} added to personal target progress`);
synthesisIgnored = false;
@ -516,16 +513,6 @@ export const addMissionInventoryUpdates = async (
}
break;
}
case "KubrowPetEggs": {
for (const egg of value) {
inventory.KubrowPetEggs ??= [];
inventory.KubrowPetEggs.push({
ItemType: egg.ItemType,
_id: new Types.ObjectId()
});
}
break;
}
case "DiscoveredMarkers": {
for (const clientMarker of value) {
const dbMarker = inventory.DiscoveredMarkers.find(x => x.tag == clientMarker.tag);
@ -615,60 +602,6 @@ export const addMissionInventoryUpdates = async (
}
break;
}
case "NemesisKillConvert":
if (inventory.Nemesis) {
inventory.NemesisHistory ??= [];
inventory.NemesisHistory.push({
// Copy over all 'base' values
fp: inventory.Nemesis.fp,
d: inventory.Nemesis.d,
manifest: inventory.Nemesis.manifest,
KillingSuit: inventory.Nemesis.KillingSuit,
killingDamageType: inventory.Nemesis.killingDamageType,
ShoulderHelmet: inventory.Nemesis.ShoulderHelmet,
WeaponIdx: inventory.Nemesis.WeaponIdx,
AgentIdx: inventory.Nemesis.AgentIdx,
BirthNode: inventory.Nemesis.BirthNode,
Faction: inventory.Nemesis.Faction,
Rank: inventory.Nemesis.Rank,
Traded: inventory.Nemesis.Traded,
PrevOwners: inventory.Nemesis.PrevOwners,
SecondInCommand: inventory.Nemesis.SecondInCommand,
Weakened: inventory.Nemesis.Weakened,
// And set killed flag
k: value.killed
});
if (value.killed) {
if (
value.weaponLoc &&
inventory.Nemesis.Faction != "FC_INFESTATION" // weaponLoc is "/Lotus/Language/Weapons/DerelictCernosName" for these for some reason
) {
const weaponType = getWeaponsForManifest(inventory.Nemesis.manifest)[
inventory.Nemesis.WeaponIdx
];
giveNemesisWeaponRecipe(
inventory,
weaponType,
value.nemesisName,
value.weaponLoc,
inventory.Nemesis.KillingSuit,
inventory.Nemesis.fp
);
}
if (value.petLoc) {
giveNemesisPetRecipe(inventory);
}
}
// TOVERIFY: Is the inbox message also sent when converting a lich? If not, how are the rewards given?
if (inventory.Nemesis.Faction == "FC_INFESTATION") {
await sendCodaFinishedMessage(inventory, inventory.Nemesis.fp, value.nemesisName, value.killed);
}
inventory.Nemesis = undefined;
}
break;
default:
// Equipment XP updates
if (equipmentKeys.includes(key as TEquipmentKey)) {
@ -931,7 +864,7 @@ export const addMissionRewards = async (
if (rewardInfo.useVaultManifest) {
MissionRewards.push({
StoreItem: getRandomElement(corruptedMods)!,
StoreItem: getRandomElement(corruptedMods),
ItemCount: 1
});
}

View File

@ -47,12 +47,12 @@ export const createGarden = (): IGardeningDatabase => {
Name: "Garden0",
Plants: [
{
PlantType: getRandomElement(plantTypes)!,
PlantType: getRandomElement(plantTypes),
EndTime: endTime,
PlotIndex: 0
},
{
PlantType: getRandomElement(plantTypes)!,
PlantType: getRandomElement(plantTypes),
EndTime: endTime,
PlotIndex: 1
}
@ -62,12 +62,12 @@ export const createGarden = (): IGardeningDatabase => {
Name: "Garden1",
Plants: [
{
PlantType: getRandomElement(plantTypes)!,
PlantType: getRandomElement(plantTypes),
EndTime: endTime,
PlotIndex: 0
},
{
PlantType: getRandomElement(plantTypes)!,
PlantType: getRandomElement(plantTypes),
EndTime: endTime,
PlotIndex: 1
}
@ -77,12 +77,12 @@ export const createGarden = (): IGardeningDatabase => {
Name: "Garden2",
Plants: [
{
PlantType: getRandomElement(plantTypes)!,
PlantType: getRandomElement(plantTypes),
EndTime: endTime,
PlotIndex: 0
},
{
PlantType: getRandomElement(plantTypes)!,
PlantType: getRandomElement(plantTypes),
EndTime: endTime,
PlotIndex: 1
}

View File

@ -6,7 +6,7 @@ export interface IRngResult {
probability: number;
}
export const getRandomElement = <T>(arr: T[]): T | undefined => {
export const getRandomElement = <T>(arr: T[]): T => {
return arr[Math.floor(Math.random() * arr.length)];
};
@ -18,10 +18,7 @@ export const getRandomInt = (min: number, max: number): number => {
return Math.floor(Math.random() * (max - min + 1)) + min;
};
export const getRewardAtPercentage = <T extends { probability: number }>(
pool: T[],
percentage: number
): T | undefined => {
const getRewardAtPercentage = <T extends { probability: number }>(pool: T[], percentage: number): T | undefined => {
if (pool.length == 0) return;
const totalChance = pool.reduce((accum, item) => accum + item.probability, 0);
@ -113,7 +110,7 @@ export class CRng {
return min;
}
randomElement<T>(arr: T[]): T | undefined {
randomElement<T>(arr: T[]): T {
return arr[Math.floor(this.random() * arr.length)];
}
@ -145,7 +142,7 @@ export class SRng {
return min;
}
randomElement<T>(arr: T[]): T | undefined {
randomElement<T>(arr: T[]): T {
return arr[this.randomInt(0, arr.length - 1)];
}

View File

@ -1,5 +1,4 @@
import { unixTimesInMs } from "@/src/constants/timeConstants";
import { catBreadHash } from "@/src/helpers/stringHelpers";
import { CRng, mixSeeds } from "@/src/services/rngService";
import { IMongoDate } from "@/src/types/commonTypes";
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
@ -7,6 +6,7 @@ import { ExportVendors, IRange } from "warframe-public-export-plus";
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
import DeimosFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosFishmongerVendorManifest.json";
import DeimosHivemindCommisionsManifestFishmonger from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestFishmonger.json";
import DeimosHivemindCommisionsManifestPetVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestPetVendor.json";
import DeimosHivemindCommisionsManifestProspector from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestProspector.json";
@ -22,10 +22,12 @@ import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorI
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
import OstronFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronFishmongerVendorManifest.json";
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json";
import RadioLegionIntermission12VendorManifest from "@/static/fixed_responses/getVendorInfo/RadioLegionIntermission12VendorManifest.json";
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
import SolarisFishmongerVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisFishmongerVendorManifest.json";
import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json";
import Temple1999VendorManifest from "@/static/fixed_responses/getVendorInfo/Temple1999VendorManifest.json";
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
@ -34,6 +36,7 @@ import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVe
const rawVendorManifests: IVendorManifest[] = [
ArchimedeanVendorManifest,
DeimosEntratiFragmentVendorProductsManifest,
DeimosFishmongerVendorManifest,
DeimosHivemindCommisionsManifestFishmonger,
DeimosHivemindCommisionsManifestPetVendor,
DeimosHivemindCommisionsManifestProspector,
@ -49,10 +52,12 @@ const rawVendorManifests: IVendorManifest[] = [
HubsRailjackCrewMemberVendorManifest,
MaskSalesmanManifest,
Nova1999ConquestShopManifest,
OstronFishmongerVendorManifest,
OstronPetVendorManifest,
OstronProspectorVendorManifest,
RadioLegionIntermission12VendorManifest,
SolarisDebtTokenVendorRepossessionsManifest,
SolarisFishmongerVendorManifest,
SolarisProspectorVendorManifest,
Temple1999VendorManifest,
TeshinHardModeVendorManifest, // uses preprocessing
@ -82,11 +87,17 @@ const generatableVendors: IGeneratableVendorInfo[] = [
cycleOffset: 1744934400_000,
cycleDuration: 4 * unixTimesInMs.day
},
{
_id: { $oid: "5be4a159b144f3cdf1c22efa" },
TypeName: "/Lotus/Types/Game/VendorManifests/Solaris/DebtTokenVendorManifest",
RandomSeedType: "VRST_FLAVOUR_TEXT",
cycleDuration: unixTimesInMs.hour
},
{
_id: { $oid: "61ba123467e5d37975aeeb03" },
TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest",
RandomSeedType: "VRST_FLAVOUR_TEXT",
cycleDuration: unixTimesInMs.week // TODO: Auto-detect this based on the items, so we don't need to specify it explicitly.
cycleDuration: unixTimesInMs.week
}
// {
// _id: { $oid: "5dbb4c41e966f7886c3ce939" },
@ -94,10 +105,6 @@ const generatableVendors: IGeneratableVendorInfo[] = [
// }
];
const getVendorOid = (typeName: string): string => {
return "5be4a159b144f3cd" + catBreadHash(typeName).toString(16).padStart(8, "0");
};
export const getVendorManifestByTypeName = (typeName: string): IVendorManifest | undefined => {
for (const vendorManifest of rawVendorManifests) {
if (vendorManifest.VendorInfo.TypeName == typeName) {
@ -109,14 +116,6 @@ export const getVendorManifestByTypeName = (typeName: string): IVendorManifest |
return generateVendorManifest(vendorInfo);
}
}
if (typeName in ExportVendors) {
return generateVendorManifest({
_id: { $oid: getVendorOid(typeName) },
TypeName: typeName,
RandomSeedType: ExportVendors[typeName].randomSeedType,
cycleDuration: unixTimesInMs.hour
});
}
return undefined;
};
@ -131,17 +130,6 @@ export const getVendorManifestByOid = (oid: string): IVendorManifest | undefined
return generateVendorManifest(vendorInfo);
}
}
for (const [typeName, manifest] of Object.entries(ExportVendors)) {
const typeNameOid = getVendorOid(typeName);
if (typeNameOid == oid) {
return generateVendorManifest({
_id: { $oid: typeNameOid },
TypeName: typeName,
RandomSeedType: manifest.randomSeedType,
cycleDuration: unixTimesInMs.hour
});
}
}
return undefined;
};
@ -207,12 +195,12 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
const rng = new CRng(mixSeeds(vendorSeed, cycleIndex));
const manifest = ExportVendors[vendorInfo.TypeName];
const offersToAdd = [];
if (manifest.numItems && !manifest.isOneBinPerCycle) {
if (manifest.numItems && manifest.numItems.minValue != manifest.numItems.maxValue) {
const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
while (processed.ItemManifest.length + offersToAdd.length < numItemsTarget) {
// TODO: Consider per-bin item limits
// TODO: Consider item probability weightings
offersToAdd.push(rng.randomElement(manifest.items)!);
offersToAdd.push(rng.randomElement(manifest.items));
}
} else {
let binThisCycle;
@ -256,7 +244,7 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
for (let i = 0; i != rawItem.numRandomItemPrices; ++i) {
let itemPrice: { type: string; count: IRange };
do {
itemPrice = rng.randomElement(manifest.randomItemPricesPerBin![rawItem.bin])!;
itemPrice = rng.randomElement(manifest.randomItemPricesPerBin![rawItem.bin]);
} while (item.ItemPrices.find(x => x.ItemType == itemPrice.type));
item.ItemPrices.push({
ItemType: itemPrice.type,
@ -275,18 +263,11 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
) * rawItem.credits.step;
item.RegularPrice = [value, value];
}
if (rawItem.platinum) {
const value =
typeof rawItem.platinum == "number"
? rawItem.platinum
: rng.randomInt(rawItem.platinum.minValue, rawItem.platinum.maxValue);
item.PremiumPrice = [value, value];
}
if (vendorInfo.RandomSeedType) {
item.LocTagRandSeed = (rng.randomInt(0, 0xffff) << 16) | rng.randomInt(0, 0xffff);
if (vendorInfo.RandomSeedType == "VRST_WEAPON") {
const highDword = (rng.randomInt(0, 0xffff) << 16) | rng.randomInt(0, 0xffff);
item.LocTagRandSeed = (BigInt(highDword) << 32n) | (BigInt(item.LocTagRandSeed) & 0xffffffffn);
item.LocTagRandSeed = (BigInt(highDword) << 32n) | BigInt(item.LocTagRandSeed);
}
}
processed.ItemManifest.push(item);

View File

@ -225,7 +225,7 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
const seed = new CRng(day).randomInt(0, 0xffff);
const rng = new CRng(seed);
const boss = rng.randomElement(sortieBosses)!;
const boss = rng.randomElement(sortieBosses);
const modifiers = [
"SORTIE_MODIFIER_LOW_ENERGY",
@ -269,10 +269,7 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
sortieFactionToFactionIndexes[sortieBossToFaction[boss]].includes(value.factionIndex!) &&
key in sortieTilesets
) {
if (
value.missionIndex != 5 && // Sorties do not have capture missions
!availableMissionIndexes.includes(value.missionIndex)
) {
if (!availableMissionIndexes.includes(value.missionIndex)) {
availableMissionIndexes.push(value.missionIndex);
}
nodes.push(key);
@ -302,7 +299,7 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
missionIndex = ExportRegions[node].missionIndex;
if (missionIndex != 28) {
missionIndex = rng.randomElement(availableMissionIndexes)!;
missionIndex = rng.randomElement(availableMissionIndexes);
}
} while (
specialMissionTypes.indexOf(missionIndex) != -1 &&
@ -312,7 +309,7 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
if (i == 2 && rng.randomInt(0, 2) == 2) {
const filteredModifiers = modifiers.filter(mod => mod !== "SORTIE_MODIFIER_MELEE_ONLY");
const modifierType = rng.randomElement(filteredModifiers)!;
const modifierType = rng.randomElement(filteredModifiers);
if (boss == "SORTIE_BOSS_PHORID") {
selectedNodes.push({
@ -346,7 +343,7 @@ const pushSortieIfRelevant = (worldState: IWorldState, day: number): void => {
? modifiers.filter(mod => mod != "SORTIE_MODIFIER_HAZARD_RADIATION")
: modifiers;
const modifierType = rng.randomElement(filteredModifiers)!;
const modifierType = rng.randomElement(filteredModifiers);
selectedNodes.push({
missionType,
@ -389,7 +386,7 @@ const getSeasonDailyChallenge = (day: number): ISeasonChallenge => {
Daily: true,
Activation: { $date: { $numberLong: dayStart.toString() } },
Expiry: { $date: { $numberLong: dayEnd.toString() } },
Challenge: rng.randomElement(dailyChallenges)!
Challenge: rng.randomElement(dailyChallenges)
};
};
@ -408,7 +405,7 @@ const getSeasonWeeklyChallenge = (week: number, id: number): ISeasonChallenge =>
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
Activation: { $date: { $numberLong: weekStart.toString() } },
Expiry: { $date: { $numberLong: weekEnd.toString() } },
Challenge: rng.randomElement(weeklyChallenges)!
Challenge: rng.randomElement(weeklyChallenges)
};
};
@ -425,7 +422,7 @@ const getSeasonWeeklyHardChallenge = (week: number, id: number): ISeasonChalleng
_id: { $oid: "67e1bb2d9d00cb47" + challengeId.toString().padStart(8, "0") },
Activation: { $date: { $numberLong: weekStart.toString() } },
Expiry: { $date: { $numberLong: weekEnd.toString() } },
Challenge: rng.randomElement(weeklyHardChallenges)!
Challenge: rng.randomElement(weeklyHardChallenges)
};
};
@ -1196,7 +1193,7 @@ export const getLiteSortie = (week: number): ILiteSortie => {
"MT_EXTERMINATION",
"MT_SABOTAGE",
"MT_RESCUE"
])!,
]),
node: firstNode
},
{
@ -1206,8 +1203,8 @@ export const getLiteSortie = (week: number): ILiteSortie => {
"MT_ARTIFACT",
"MT_EXCAVATE",
"MT_SURVIVAL"
])!,
node: rng.randomElement(nodes)!
]),
node: rng.randomElement(nodes)
},
{
missionType: "MT_ASSASSINATION",

View File

@ -43,7 +43,6 @@ export interface IInventoryDatabase
| "RecentVendorPurchases"
| "NextRefill"
| "Nemesis"
| "NemesisHistory"
| "EntratiVaultCountResetDate"
| "BrandedSuits"
| "LockedWeaponGroup"
@ -52,7 +51,6 @@ export interface IInventoryDatabase
| "LastLiteSortieReward"
| "CrewMembers"
| "QualifyingInvasions"
| "LastInventorySync"
| TEquipmentKey
>,
InventoryDatabaseEquipment {
@ -81,7 +79,6 @@ export interface IInventoryDatabase
RecentVendorPurchases?: IRecentVendorPurchaseDatabase[];
NextRefill?: Date;
Nemesis?: INemesisDatabase;
NemesisHistory?: INemesisBaseDatabase[];
EntratiVaultCountResetDate?: Date;
BrandedSuits?: Types.ObjectId[];
LockedWeaponGroup?: ILockedWeaponGroupDatabase;
@ -90,7 +87,6 @@ export interface IInventoryDatabase
LastLiteSortieReward?: ILastSortieRewardDatabase[];
CrewMembers: ICrewMemberDatabase[];
QualifyingInvasions: IInvasionProgressDatabase[];
LastInventorySync?: Types.ObjectId;
}
export interface IQuestKeyDatabase {
@ -260,7 +256,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
EquippedGear: string[];
DeathMarks: string[];
FusionTreasures: IFusionTreasure[];
//WebFlags: IWebFlags;
WebFlags: IWebFlags;
CompletedAlerts: string[];
Consumables: ITypeCount[];
LevelKeys: ITypeCount[];
@ -270,10 +266,10 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
KubrowPetEggs?: IKubrowPetEggClient[];
LoreFragmentScans: ILoreFragmentScan[];
EquippedEmotes: string[];
//PendingTrades: IPendingTrade[];
PendingTrades: IPendingTrade[];
Boosters: IBooster[];
ActiveDojoColorResearch: string;
//SentientSpawnChanceBoosters: ISentientSpawnChanceBoosters;
SentientSpawnChanceBoosters: ISentientSpawnChanceBoosters;
SupportedSyndicate?: string;
Affiliations: IAffiliation[];
QualifyingInvasions: IInvasionProgressClient[];
@ -295,19 +291,19 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
ActiveAvatarImageType: string;
ShipDecorations: ITypeCount[];
DiscoveredMarkers: IDiscoveredMarker[];
//CompletedJobs: ICompletedJob[];
CompletedJobs: ICompletedJob[];
FocusAbility?: string;
FocusUpgrades: IFocusUpgrade[];
HasContributedToDojo?: boolean;
HWIDProtectEnabled?: boolean;
//KubrowPetPrints: IKubrowPetPrint[];
KubrowPetPrints: IKubrowPetPrint[];
AlignmentReplay?: IAlignment;
//PersonalGoalProgress: IPersonalGoalProgress[];
PersonalGoalProgress: IPersonalGoalProgress[];
ThemeStyle: string;
ThemeBackground: string;
ThemeSounds: string;
BountyScore: number;
//ChallengeInstanceStates: IChallengeInstanceState[];
ChallengeInstanceStates: IChallengeInstanceState[];
LoginMilestoneRewards: string[];
RecentVendorPurchases?: IRecentVendorPurchaseClient[];
NodeIntrosCompleted: string[];
@ -315,17 +311,17 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
CompletedJobChains?: ICompletedJobChain[];
SeasonChallengeHistory: ISeasonChallenge[];
EquippedInstrument?: string;
//InvasionChainProgress: IInvasionChainProgress[];
InvasionChainProgress: IInvasionChainProgress[];
Nemesis?: INemesisClient;
NemesisHistory?: INemesisBaseClient[];
//LastNemesisAllySpawnTime?: IMongoDate;
NemesisHistory: INemesisBaseClient[];
LastNemesisAllySpawnTime?: IMongoDate;
Settings?: ISettings;
PersonalTechProjects: IPersonalTechProjectClient[];
PlayerSkills: IPlayerSkills;
CrewShipAmmo: ITypeCount[];
CrewShipWeaponSkins: IUpgradeClient[];
CrewShipSalvagedWeaponSkins: IUpgradeClient[];
//TradeBannedUntil?: IMongoDate;
TradeBannedUntil?: IMongoDate;
PlayedParkourTutorial: boolean;
SubscribedToEmailsPersonalized: number;
InfestedFoundry?: IInfestedFoundryClient;
@ -335,17 +331,17 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
LotusCustomization?: ILotusCustomization;
UseAdultOperatorLoadout?: boolean;
NemesisAbandonedRewards: string[];
LastInventorySync?: IOid;
LastInventorySync: IOid;
NextRefill?: IMongoDate;
FoundToday?: IMiscItem[]; // for Argon Crystals
CustomMarkers?: ICustomMarkers[];
//ActiveLandscapeTraps: any[];
ActiveLandscapeTraps: any[];
EvolutionProgress?: IEvolutionProgress[];
//RepVotes: any[];
//LeagueTickets: any[];
//Quests: any[];
//Robotics: any[];
//UsedDailyDeals: any[];
RepVotes: any[];
LeagueTickets: any[];
Quests: any[];
Robotics: any[];
UsedDailyDeals: any[];
LibraryPersonalTarget?: string;
LibraryPersonalProgress: ILibraryPersonalProgress[];
CollectibleSeries?: ICollectibleEntry[];
@ -906,8 +902,8 @@ export interface IPendingRecipeDatabase {
ItemType: string;
CompletionDate: Date;
ItemId: IOid;
TargetItemId?: string; // unsure what this is for
TargetFingerprint?: string;
TargetItemId?: string; // likely related to liches
TargetFingerprint?: string; // likely related to liches
LongGuns?: IEquipmentDatabase[];
Pistols?: IEquipmentDatabase[];
Melee?: IEquipmentDatabase[];
@ -955,17 +951,6 @@ export interface ICrewShipComponentFingerprint extends IInnateDamageFingerprint
SubroutineIndex?: number;
}
export interface INemesisWeaponTargetFingerprint {
ItemType: string;
UpgradeFingerprint: IInnateDamageFingerprint;
Name: string;
}
export interface INemesisPetTargetFingerprint {
Parts: string[];
Name: string;
}
export enum GettingSlotOrderInfo {
Empty = "",
LotusUpgradesModsRandomizedPlayerMeleeWeaponRandomModRare0 = "/Lotus/Upgrades/Mods/Randomized/PlayerMeleeWeaponRandomModRare:0",

View File

@ -21,9 +21,7 @@ import {
ILockedWeaponGroupClient,
ILoadOutPresets,
IInvasionProgressClient,
IWeaponSkinClient,
IKubrowPetEggClient,
INemesisClient
IWeaponSkinClient
} from "./inventoryTypes/inventoryTypes";
import { IGroup } from "./loginTypes";
@ -75,14 +73,6 @@ export type IMissionInventoryUpdateRequest = {
PS: string;
ActiveDojoColorResearch: string;
RewardInfo?: IRewardInfo;
NemesisKillConvert?: {
nemesisName: string;
weaponLoc: string;
petLoc: "" | "/Lotus/Language/Pets/ZanukaPetName";
fingerprint: bigint | number;
killed: boolean;
};
target?: INemesisClient;
ReceivedCeremonyMsg: boolean;
LastCeremonyResetDate: number;
MissionPTS: number;
@ -128,7 +118,6 @@ export type IMissionInventoryUpdateRequest = {
NumExtraRewards: number;
Count: number;
}[];
KubrowPetEggs?: IKubrowPetEggClient[];
DiscoveredMarkers?: IDiscoveredMarker[];
LockedWeaponGroup?: ILockedWeaponGroupClient; // sent when captured by zanuka
UnlockWeapons?: boolean; // sent when recovered weapons from zanuka capture

View File

@ -1097,5 +1097,7 @@
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLamp",
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLampLarge",
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLampSmall",
"/Lotus/Types/LevelObjects/InfestedPumpkinExplosiveTotem"
"/Lotus/Types/LevelObjects/InfestedPumpkinExplosiveTotem",
"/Lotus/Types/Enemies/Orokin/OrokinMoaBipedAvatar",
"/Lotus/Types/Enemies/Grineer/AIWeek/Avatars/BeastMasterAvatar"
]

View File

@ -0,0 +1,106 @@
{
"VendorInfo": {
"_id": {
"$oid": "5f456e01c96976e97d6b8016"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/FishmongerVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosOrokinFishAPartItem",
"PremiumPrice": [9, 9],
"Bin": "BIN_1",
"QuantityMultiplier": 10,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e91b9"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishDPartItem",
"PremiumPrice": [17, 17],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e91ba"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishCPartItem",
"PremiumPrice": [10, 10],
"Bin": "BIN_1",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e91bb"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishBPartItem",
"PremiumPrice": [6, 6],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e91bc"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosInfestedFishAPartItem",
"PremiumPrice": [5, 5],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e91bd"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Deimos/FishParts/DeimosGenericSharedFishPartItem",
"PremiumPrice": [7, 7],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e91be"
}
}
],
"PropertyTextHash": "6DF13A7FB573C25B4B4F989CBEFFC615",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -0,0 +1,106 @@
{
"VendorInfo": {
"_id": {
"$oid": "59d6e27ebcc718474eb17115"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Ostron/FishmongerVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayUncommonFishAPartItem",
"PremiumPrice": [14, 14],
"Bin": "BIN_1",
"QuantityMultiplier": 10,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9808"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/BothUncommonFishBPartItem",
"PremiumPrice": [12, 12],
"Bin": "BIN_1",
"QuantityMultiplier": 10,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9809"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayCommonFishCPartItem",
"PremiumPrice": [8, 8],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e980a"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayCommonFishBPartItem",
"PremiumPrice": [7, 7],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e980b"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/DayCommonFishAPartItem",
"PremiumPrice": [10, 10],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e980c"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Eidolon/FishParts/BothCommonFishBPartItem",
"PremiumPrice": [8, 8],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e980d"
}
}
],
"PropertyTextHash": "CC3B9DAFB38F412998E90A41421A8986",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -0,0 +1,106 @@
{
"VendorInfo": {
"_id": {
"$oid": "5b0de8556df82a56ea9bae82"
},
"TypeName": "/Lotus/Types/Game/VendorManifests/Solaris/FishmongerVendorManifest",
"ItemManifest": [
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishThermalLaserItem",
"PremiumPrice": [15, 15],
"Bin": "BIN_1",
"QuantityMultiplier": 10,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9515"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishVenedoCaseItem",
"PremiumPrice": [8, 8],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9516"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/SolarisFishDissipatorCoilItem",
"PremiumPrice": [18, 18],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9517"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishExaBrainItem",
"PremiumPrice": [5, 5],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9518"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/CorpusFishAnoscopicSensorItem",
"PremiumPrice": [5, 5],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e9519"
}
},
{
"StoreItem": "/Lotus/StoreItems/Types/Items/Fish/Solaris/FishParts/GenericFishScrapItem",
"PremiumPrice": [5, 5],
"Bin": "BIN_0",
"QuantityMultiplier": 20,
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
},
"AllowMultipurchase": true,
"Id": {
"$oid": "66fd60b20ba592c4c95e951a"
}
}
],
"PropertyTextHash": "946131D0CF5CDF7C2C03BB967DE0DF49",
"Expiry": {
"$date": {
"$numberLong": "9999999000000"
}
}
}
}

View File

@ -674,10 +674,6 @@
<input class="form-check-input" type="checkbox" id="noResourceExtractorDronesDamage" />
<label class="form-check-label" for="noResourceExtractorDronesDamage" data-loc="cheats_noResourceExtractorDronesDamage"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="skipClanKeyCrafting" />
<label class="form-check-label" for="skipClanKeyCrafting" data-loc="cheats_skipClanKeyCrafting"></label>
</div>
<div class="form-check">
<input class="form-check-input" type="checkbox" id="noDojoRoomBuildStage" />
<label class="form-check-label" for="noDojoRoomBuildStage" data-loc="cheats_noDojoRoomBuildStage"></label>

View File

@ -375,7 +375,6 @@ function fetchItemList() {
}
fetchItemList();
// Assumes that caller revalidates authz
function updateInventory() {
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
req.done(data => {
@ -488,7 +487,6 @@ function updateInventory() {
a.href = "#";
a.onclick = function (event) {
event.preventDefault();
revalidateAuthz(() => {
if (item.XP < maxXP) {
addGearExp(category, item.ItemId.$oid, maxXP - item.XP);
}
@ -508,7 +506,6 @@ function updateInventory() {
}
}
}
});
};
a.title = loc("code_maxRank");
a.innerHTML = `<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 384 512"><!--!Font Awesome Free 6.5.2 by @fontawesome - https://fontawesome.com License - https://fontawesome.com/license/free Copyright 2024 Fonticons, Inc.--><path d="M214.6 41.4c-12.5-12.5-32.8-12.5-45.3 0l-160 160c-12.5 12.5-12.5 32.8 0 45.3s32.8 12.5 45.3 0L160 141.2V448c0 17.7 14.3 32 32 32s32-14.3 32-32V141.2L329.4 246.6c12.5 12.5 32.8 12.5 45.3 0s12.5-32.8 0-45.3l-160-160z"/></svg>`;
@ -1232,8 +1229,8 @@ function addMissingEvolutionProgress() {
}
function maxRankAllEvolutions() {
revalidateAuthz(() => {
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
req.done(data => {
const requests = [];
@ -1252,12 +1249,11 @@ function maxRankAllEvolutions() {
toast(loc("code_noEquipmentToRankUp"));
});
});
}
function maxRankAllEquipment(categories) {
revalidateAuthz(() => {
const req = $.get("/api/inventory.php?" + window.authz + "&xpBasedLevelCapDisabled=1");
req.done(data => {
window.itemListPromise.then(itemMap => {
const batchData = {};
@ -1286,8 +1282,7 @@ function maxRankAllEquipment(categories) {
for (const exaltedType of itemMap[item.ItemType].exalted) {
const exaltedItem = data["SpecialItems"].find(x => x.ItemType == exaltedType);
if (exaltedItem) {
const exaltedCap =
itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
const exaltedCap = itemMap[exaltedType]?.type == "weapons" ? 800_000 : 1_600_000;
if (exaltedItem.XP < exaltedCap) {
batchData["SpecialItems"] ??= [];
batchData["SpecialItems"].push({
@ -1309,10 +1304,8 @@ function maxRankAllEquipment(categories) {
toast(loc("code_noEquipmentToRankUp"));
});
});
});
}
// Assumes that caller revalidates authz
function addGearExp(category, oid, xp) {
const data = {};
data[category] = [
@ -1321,6 +1314,7 @@ function addGearExp(category, oid, xp) {
XP: xp
}
];
revalidateAuthz(() => {
$.post({
url: "/custom/addXp?" + window.authz,
contentType: "application/json",
@ -1330,6 +1324,7 @@ function addGearExp(category, oid, xp) {
updateInventory();
}
});
});
}
function sendBatchGearExp(data) {
@ -1603,7 +1598,6 @@ function doAcquireMod() {
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
function doChangeSettings() {
revalidateAuthz(() => {
fetch("/custom/config?" + window.authz)
.then(response => response.json())
.then(json => {
@ -1630,7 +1624,6 @@ function doChangeSettings() {
updateInventory();
});
});
});
}
// Cheats route
@ -1883,7 +1876,6 @@ function doChangeSupportedSyndicate() {
}
function doAddCurrency(currency) {
revalidateAuthz(() => {
$.post({
url: "/custom/addCurrency?" + window.authz,
contentType: "application/json",
@ -1894,29 +1886,24 @@ function doAddCurrency(currency) {
}).then(function () {
updateInventory();
});
});
}
function doQuestUpdate(operation, itemType) {
revalidateAuthz(() => {
$.post({
url: "/custom/manageQuests?" + window.authz + "&operation=" + operation + "&itemType=" + itemType,
contentType: "application/json"
}).then(function () {
updateInventory();
});
});
}
function doBulkQuestUpdate(operation) {
revalidateAuthz(() => {
$.post({
url: "/custom/manageQuests?" + window.authz + "&operation=" + operation,
contentType: "application/json"
}).then(function () {
updateInventory();
});
});
}
function toast(text) {

View File

@ -34,8 +34,8 @@ dict = {
code_rerollsNumber: `Anzahl der Umrollversuche`,
code_viewStats: `Statistiken anzeigen`,
code_rank: `Rang`,
code_rankUp: `Rang erhöhen`,
code_rankDown: `Rang verringern`,
code_rankUp: `[UNTRANSLATED] Rank up`,
code_rankDown: `[UNTRANSLATED] Rank down`,
code_count: `Anzahl`,
code_focusAllUnlocked: `Alle Fokus-Schulen sind bereits freigeschaltet.`,
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.`,
@ -84,23 +84,23 @@ dict = {
inventory_sentinelWeapons: `Wächter-Waffen`,
inventory_operatorAmps: `Verstärker`,
inventory_hoverboards: `K-Drives`,
inventory_moaPets: `Moas`,
inventory_moaPets: `Moa`,
inventory_kubrowPets: `Bestien`,
inventory_evolutionProgress: `Incarnon-Entwicklungsfortschritte`,
inventory_evolutionProgress: `[UNTRANSLATED] Incarnon Evolution Progress`,
inventory_bulkAddSuits: `Fehlende Warframes hinzufügen`,
inventory_bulkAddWeapons: `Fehlende Waffen hinzufügen`,
inventory_bulkAddSpaceSuits: `Fehlende Archwings hinzufügen`,
inventory_bulkAddSpaceWeapons: `Fehlende Archwing-Waffen hinzufügen`,
inventory_bulkAddSentinels: `Fehlende Wächter hinzufügen`,
inventory_bulkAddSentinelWeapons: `Fehlende Wächter-Waffen hinzufügen`,
inventory_bulkAddEvolutionProgress: `Fehlende Incarnon-Entwicklungsfortschritte hinzufügen`,
inventory_bulkAddEvolutionProgress: `[UNTRANSLATED] Add Missing Incarnon Evolution Progress`,
inventory_bulkRankUpSuits: `Alle Warframes auf Max. Rang`,
inventory_bulkRankUpWeapons: `Alle Waffen auf Max. Rang`,
inventory_bulkRankUpSpaceSuits: `Alle Archwings auf Max. Rang`,
inventory_bulkRankUpSpaceWeapons: `Alle Archwing-Waffen auf Max. Rang`,
inventory_bulkRankUpSentinels: `Alle Wächter auf Max. Rang`,
inventory_bulkRankUpSentinelWeapons: `Alle Wächter-Waffen auf Max. Rang`,
inventory_bulkRankUpEvolutionProgress: `Alle Incarnon-Entwicklungsfortschritte auf Max. Rang`,
inventory_bulkRankUpEvolutionProgress: `[UNTRANSLATED] Max Rank All Incarnon Evolution Progress`,
quests_list: `Quests`,
quests_completeAll: `Alle Quests abschließen`,
@ -120,9 +120,9 @@ dict = {
mods_fingerprintHelp: `Benötigst du Hilfe mit dem Fingerabdruck?`,
mods_rivens: `Rivens`,
mods_mods: `Mods`,
mods_addMissingUnrankedMods: `Fehlende Mods ohne Rang hinzufügen`,
mods_addMissingUnrankedMods: `[UNTRANSLATED] Add Missing Unranked Mods`,
mods_removeUnranked: `Mods ohne Rang entfernen`,
mods_addMissingMaxRankMods: `Fehlende Mods mit Max. Rang hinzufügen`,
mods_addMissingMaxRankMods: `[UNTRANSLATED] Add Missing Max Rank Mods`,
cheats_administratorRequirement: `Du musst Administrator sein, um diese Funktion nutzen zu können. Um Administrator zu werden, füge <code>|DISPLAYNAME|</code> zu <code>administratorNames</code> in der config.json hinzu.`,
cheats_server: `Server`,
cheats_skipTutorial: `Tutorial überspringen`,
@ -134,7 +134,7 @@ dict = {
cheats_infiniteEndo: `Unendlich Endo`,
cheats_infiniteRegalAya: `Unendlich Reines Aya`,
cheats_infiniteHelminthMaterials: `Unendlich Helminth-Materialien`,
cheats_dontSubtractConsumables: `Verbrauchsgegenstände (Ausrüstung) nicht verbrauchen`,
cheats_dontSubtractConsumables: `[UNTRANSLATED] Don't Subtract Consumables`,
cheats_unlockAllShipFeatures: `Alle Schiffs-Funktionen freischalten`,
cheats_unlockAllShipDecorations: `Alle Schiffsdekorationen freischalten`,
cheats_unlockAllFlavourItems: `Alle <abbr title=\"Animationssets, Glyphen, Farbpaletten usw.\">Sammlerstücke</abbr> freischalten`,
@ -154,7 +154,6 @@ dict = {
cheats_noKimCooldowns: `Keine Wartezeit bei KIM`,
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,
cheats_skipClanKeyCrafting: `Clan-Schlüsselherstellung überspringen`,
cheats_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`,
cheats_noDojoDecoBuildStage: `Kein Dojo-Deko-Bauvorgang`,
cheats_fastDojoRoomDestruction: `Schnelle Dojo-Raum-Zerstörung`,

View File

@ -83,7 +83,7 @@ dict = {
inventory_sentinelWeapons: `Sentinel Weapons`,
inventory_operatorAmps: `Amps`,
inventory_hoverboards: `K-Drives`,
inventory_moaPets: `Moas`,
inventory_moaPets: `Moa`,
inventory_kubrowPets: `Beasts`,
inventory_evolutionProgress: `Incarnon Evolution Progress`,
inventory_bulkAddSuits: `Add Missing Warframes`,
@ -153,7 +153,6 @@ dict = {
cheats_noKimCooldowns: `No KIM Cooldowns`,
cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`,
cheats_noResourceExtractorDronesDamage: `No Resource Extractor Drones Damage`,
cheats_skipClanKeyCrafting: `Skip Clan Key Crafting`,
cheats_noDojoRoomBuildStage: `No Dojo Room Build Stage`,
cheats_noDojoDecoBuildStage: `No Dojo Deco Build Stage`,
cheats_fastDojoRoomDestruction: `Fast Dojo Room Destruction`,

View File

@ -84,7 +84,7 @@ dict = {
inventory_sentinelWeapons: `Armas de centinela`,
inventory_operatorAmps: `Amps`,
inventory_hoverboards: `K-Drives`,
inventory_moaPets: `Moas`,
inventory_moaPets: `Moa`,
inventory_kubrowPets: `Bestias`,
inventory_evolutionProgress: `Progreso de evolución Incarnon`,
inventory_bulkAddSuits: `Agregar Warframes faltantes`,
@ -154,7 +154,6 @@ dict = {
cheats_noKimCooldowns: `Sin tiempo de espera para conversaciones KIM`,
cheats_instantResourceExtractorDrones: `Drones de extracción de recursos instantáneos`,
cheats_noResourceExtractorDronesDamage: `Sin daño a los drones extractores de recursos`,
cheats_skipClanKeyCrafting: `Saltar la fabricación de la llave de clan`,
cheats_noDojoRoomBuildStage: `Sin etapa de construcción de sala del dojo`,
cheats_noDojoDecoBuildStage: `Sin etapa de construcción de decoraciones del dojo`,
cheats_fastDojoRoomDestruction: `Destrucción rápida de salas del dojo`,

View File

@ -84,7 +84,7 @@ dict = {
inventory_sentinelWeapons: `Armes de sentinelles`,
inventory_operatorAmps: `Amplificateurs`,
inventory_hoverboards: `K-Drives`,
inventory_moaPets: `Moas`,
inventory_moaPets: `Moa`,
inventory_kubrowPets: `Bêtes`,
inventory_evolutionProgress: `[UNTRANSLATED] Incarnon Evolution Progress`,
inventory_bulkAddSuits: `Ajouter les Warframes manquantes`,
@ -154,7 +154,6 @@ dict = {
cheats_noKimCooldowns: `Aucun cooldown sur le KIM`,
cheats_instantResourceExtractorDrones: `Ressources de drones d'extraction instantannées`,
cheats_noResourceExtractorDronesDamage: `Aucun dégâts aux drones d'extraction de resources`,
cheats_skipClanKeyCrafting: `[UNTRANSLATED] Skip Clan Key Crafting`,
cheats_noDojoRoomBuildStage: `Aucune attente (construction des salles)`,
cheats_noDojoDecoBuildStage: `Aucune attente (construction des décorations)`,
cheats_fastDojoRoomDestruction: `Destruction de salle instantanée (Dojo)`,

View File

@ -154,7 +154,6 @@ dict = {
cheats_noKimCooldowns: `Чаты KIM без кулдауна`,
cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`,
cheats_noResourceExtractorDronesDamage: `Без урона по дронам-сборщикам`,
cheats_skipClanKeyCrafting: `[UNTRANSLATED] Skip Clan Key Crafting`,
cheats_noDojoRoomBuildStage: `Мгновенное Строительтво Комнат Додзё`,
cheats_noDojoDecoBuildStage: `Мгновенное Строительтво Декораций Додзё`,
cheats_fastDojoRoomDestruction: `Мгновенные Уничтожение Комнат Додзё`,

View File

@ -154,7 +154,6 @@ dict = {
cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`,
cheats_instantResourceExtractorDrones: `即时资源采集无人机`,
cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`,
cheats_skipClanKeyCrafting: `[UNTRANSLATED] Skip Clan Key Crafting`,
cheats_noDojoRoomBuildStage: `无视道场房间建造阶段`,
cheats_noDojoDecoBuildStage: `[UNTRANSLATED] No Dojo Deco Build Stage`,
cheats_fastDojoRoomDestruction: `快速拆除道场房间`,