merge upstream
This commit is contained in:
commit
8d729386a0
@ -4,7 +4,7 @@
|
|||||||
"description": "WF Emulator",
|
"description": "WF Emulator",
|
||||||
"main": "index.ts",
|
"main": "index.ts",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
"start": "node --import ./build/src/pathman.js build/src/index.js",
|
"start": "node --enable-source-maps --import ./build/src/pathman.js build/src/index.js",
|
||||||
"dev": "ts-node-dev --openssl-legacy-provider -r tsconfig-paths/register src/index.ts ",
|
"dev": "ts-node-dev --openssl-legacy-provider -r tsconfig-paths/register src/index.ts ",
|
||||||
"build": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
|
"build": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
|
||||||
"verify": "tsgo --noEmit",
|
"verify": "tsgo --noEmit",
|
||||||
|
30
src/controllers/api/addIgnoredUserController.ts
Normal file
30
src/controllers/api/addIgnoredUserController.ts
Normal file
@ -0,0 +1,30 @@
|
|||||||
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { Account, Ignore } from "@/src/models/loginModel";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { IFriendInfo } from "@/src/types/guildTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const addIgnoredUserController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const data = getJSONfromString<IAddIgnoredUserRequest>(String(req.body));
|
||||||
|
const ignoreeAccount = await Account.findOne(
|
||||||
|
{ DisplayName: data.playerName.substring(0, data.playerName.length - 1) },
|
||||||
|
"_id"
|
||||||
|
);
|
||||||
|
if (ignoreeAccount) {
|
||||||
|
await Ignore.create({ ignorer: accountId, ignoree: ignoreeAccount._id });
|
||||||
|
res.json({
|
||||||
|
Ignored: {
|
||||||
|
_id: toOid(ignoreeAccount._id),
|
||||||
|
DisplayName: data.playerName
|
||||||
|
} satisfies IFriendInfo
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
res.status(400).end();
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IAddIgnoredUserRequest {
|
||||||
|
playerName: string;
|
||||||
|
}
|
@ -18,6 +18,7 @@ import {
|
|||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
|
|
||||||
interface IClaimCompletedRecipeRequest {
|
interface IClaimCompletedRecipeRequest {
|
||||||
RecipeIds: IOid[];
|
RecipeIds: IOid[];
|
||||||
@ -80,6 +81,7 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
} else {
|
} else {
|
||||||
logger.debug("Claiming Recipe", { recipe, pendingRecipe });
|
logger.debug("Claiming Recipe", { recipe, pendingRecipe });
|
||||||
|
|
||||||
|
let BrandedSuits: undefined | IOid[];
|
||||||
if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
|
if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") {
|
||||||
inventory.PendingSpectreLoadouts ??= [];
|
inventory.PendingSpectreLoadouts ??= [];
|
||||||
inventory.SpectreLoadouts ??= [];
|
inventory.SpectreLoadouts ??= [];
|
||||||
@ -104,9 +106,10 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
inventory.BrandedSuits!.findIndex(x => x.equals(pendingRecipe.SuitToUnbrand)),
|
inventory.BrandedSuits!.findIndex(x => x.equals(pendingRecipe.SuitToUnbrand)),
|
||||||
1
|
1
|
||||||
);
|
);
|
||||||
|
BrandedSuits = [toOid(pendingRecipe.SuitToUnbrand!)];
|
||||||
}
|
}
|
||||||
|
|
||||||
let InventoryChanges = {};
|
let InventoryChanges: IInventoryChanges = {};
|
||||||
if (recipe.consumeOnUse) {
|
if (recipe.consumeOnUse) {
|
||||||
addRecipes(inventory, [
|
addRecipes(inventory, [
|
||||||
{
|
{
|
||||||
@ -134,6 +137,6 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) =
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
res.json({ InventoryChanges });
|
res.json({ InventoryChanges, BrandedSuits });
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
28
src/controllers/api/crewMembersController.ts
Normal file
28
src/controllers/api/crewMembersController.ts
Normal file
@ -0,0 +1,28 @@
|
|||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { getInventory } from "@/src/services/inventoryService";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { ICrewMemberClient } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
|
export const crewMembersController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountIdForRequest(req);
|
||||||
|
const inventory = await getInventory(accountId, "CrewMembers");
|
||||||
|
const data = getJSONfromString<ICrewMembersRequest>(String(req.body));
|
||||||
|
const dbCrewMember = inventory.CrewMembers.id(data.crewMember.ItemId.$oid)!;
|
||||||
|
dbCrewMember.AssignedRole = data.crewMember.AssignedRole;
|
||||||
|
dbCrewMember.SkillEfficiency = data.crewMember.SkillEfficiency;
|
||||||
|
dbCrewMember.WeaponConfigIdx = data.crewMember.WeaponConfigIdx;
|
||||||
|
dbCrewMember.WeaponId = new Types.ObjectId(data.crewMember.WeaponId.$oid);
|
||||||
|
dbCrewMember.Configs = data.crewMember.Configs;
|
||||||
|
dbCrewMember.SecondInCommand = data.crewMember.SecondInCommand;
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
crewMemberId: data.crewMember.ItemId.$oid,
|
||||||
|
NemesisFingerprint: data.crewMember.NemesisFingerprint
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
interface ICrewMembersRequest {
|
||||||
|
crewMember: ICrewMemberClient;
|
||||||
|
}
|
@ -12,6 +12,7 @@ import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
|||||||
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
import { IInventoryChanges } from "@/src/types/purchaseTypes";
|
||||||
import { getRandomInt } from "@/src/services/rngService";
|
import { getRandomInt } from "@/src/services/rngService";
|
||||||
import { IFingerprintStat } from "@/src/helpers/rivenHelper";
|
import { IFingerprintStat } from "@/src/helpers/rivenHelper";
|
||||||
|
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
|
|
||||||
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
|
export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => {
|
||||||
const accountId = await getAccountIdForRequest(req);
|
const accountId = await getAccountIdForRequest(req);
|
||||||
@ -42,7 +43,9 @@ export const crewShipIdentifySalvageController: RequestHandler = async (req, res
|
|||||||
);
|
);
|
||||||
} else {
|
} else {
|
||||||
const meta = ExportRailjackWeapons[payload.ItemType];
|
const meta = ExportRailjackWeapons[payload.ItemType];
|
||||||
const upgradeType = meta.defaultUpgrades![0].ItemType;
|
let defaultOverwrites: Partial<IEquipmentDatabase> | undefined;
|
||||||
|
if (meta.defaultUpgrades?.[0]) {
|
||||||
|
const upgradeType = meta.defaultUpgrades[0].ItemType;
|
||||||
const upgradeMeta = ExportUpgrades[upgradeType];
|
const upgradeMeta = ExportUpgrades[upgradeType];
|
||||||
const buffs: IFingerprintStat[] = [];
|
const buffs: IFingerprintStat[] = [];
|
||||||
for (const buff of upgradeMeta.upgradeEntries!) {
|
for (const buff of upgradeMeta.upgradeEntries!) {
|
||||||
@ -51,13 +54,22 @@ export const crewShipIdentifySalvageController: RequestHandler = async (req, res
|
|||||||
Value: Math.trunc(Math.random() * 0x40000000)
|
Value: Math.trunc(Math.random() * 0x40000000)
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
addEquipment(inventory, "CrewShipSalvagedWeapons", payload.ItemType, undefined, inventoryChanges, {
|
defaultOverwrites = {
|
||||||
UpgradeType: upgradeType,
|
UpgradeType: upgradeType,
|
||||||
UpgradeFingerprint: JSON.stringify({
|
UpgradeFingerprint: JSON.stringify({
|
||||||
compat: payload.ItemType,
|
compat: payload.ItemType,
|
||||||
buffs
|
buffs
|
||||||
} satisfies IInnateDamageFingerprint)
|
} satisfies IInnateDamageFingerprint)
|
||||||
});
|
};
|
||||||
|
}
|
||||||
|
addEquipment(
|
||||||
|
inventory,
|
||||||
|
"CrewShipSalvagedWeapons",
|
||||||
|
payload.ItemType,
|
||||||
|
undefined,
|
||||||
|
inventoryChanges,
|
||||||
|
defaultOverwrites
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
inventoryChanges.CrewShipRawSalvage = [
|
inventoryChanges.CrewShipRawSalvage = [
|
||||||
|
@ -1,16 +1,20 @@
|
|||||||
|
import { toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
|
import { Account, Ignore } from "@/src/models/loginModel";
|
||||||
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
|
import { IFriendInfo } from "@/src/types/guildTypes";
|
||||||
|
import { parallelForeach } from "@/src/utils/async-utils";
|
||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
const getIgnoredUsersController: RequestHandler = (_req, res) => {
|
export const getIgnoredUsersController: RequestHandler = async (req, res) => {
|
||||||
res.writeHead(200, {
|
const accountId = await getAccountIdForRequest(req);
|
||||||
"Content-Type": "text/html",
|
const ignores = await Ignore.find({ ignorer: accountId });
|
||||||
"Content-Length": "3"
|
const ignoredUsers: IFriendInfo[] = [];
|
||||||
|
await parallelForeach(ignores, async ignore => {
|
||||||
|
const ignoreeAccount = (await Account.findById(ignore.ignoree, "DisplayName"))!;
|
||||||
|
ignoredUsers.push({
|
||||||
|
_id: toOid(ignore.ignoree),
|
||||||
|
DisplayName: ignoreeAccount.DisplayName + ""
|
||||||
});
|
});
|
||||||
res.end(
|
});
|
||||||
Buffer.from([
|
res.json({ IgnoredUsers: ignoredUsers });
|
||||||
0x7b, 0x22, 0x4e, 0x6f, 0x6e, 0x63, 0x65, 0x22, 0x3a, 0x38, 0x33, 0x30, 0x34, 0x30, 0x37, 0x37, 0x32, 0x32,
|
|
||||||
0x34, 0x30, 0x32, 0x32, 0x32, 0x36, 0x31, 0x35, 0x30, 0x31, 0x7d
|
|
||||||
])
|
|
||||||
);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
export { getIgnoredUsersController };
|
|
||||||
|
@ -97,6 +97,19 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
res.end();
|
res.end();
|
||||||
} else {
|
} else {
|
||||||
const recipe = ExportDojoRecipes.research[data.RecipeType];
|
const recipe = ExportDojoRecipes.research[data.RecipeType];
|
||||||
|
if (data.TechProductCategory) {
|
||||||
|
if (
|
||||||
|
data.TechProductCategory != "CrewShipWeapons" &&
|
||||||
|
data.TechProductCategory != "CrewShipWeaponSkins"
|
||||||
|
) {
|
||||||
|
throw new Error(`unexpected TechProductCategory: ${data.TechProductCategory}`);
|
||||||
|
}
|
||||||
|
if (!inventory[getSalvageCategory(data.TechProductCategory)].id(data.CategoryItemId)) {
|
||||||
|
throw new Error(
|
||||||
|
`no item with id ${data.CategoryItemId} in ${getSalvageCategory(data.TechProductCategory)} array`
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
const techProject =
|
const techProject =
|
||||||
inventory.PersonalTechProjects[
|
inventory.PersonalTechProjects[
|
||||||
inventory.PersonalTechProjects.push({
|
inventory.PersonalTechProjects.push({
|
||||||
@ -347,6 +360,22 @@ export const guildTechController: RequestHandler = async (req, res) => {
|
|||||||
res.json({
|
res.json({
|
||||||
inventoryChanges: inventoryChanges
|
inventoryChanges: inventoryChanges
|
||||||
});
|
});
|
||||||
|
} else if (data.Action == "InstantFinish") {
|
||||||
|
if (data.TechProductCategory != "CrewShipWeapons" && data.TechProductCategory != "CrewShipWeaponSkins") {
|
||||||
|
throw new Error(`unexpected TechProductCategory: ${data.TechProductCategory}`);
|
||||||
|
}
|
||||||
|
const inventoryChanges = finishComponentRepair(inventory, data.TechProductCategory, data.CategoryItemId!);
|
||||||
|
inventoryChanges.MiscItems = [
|
||||||
|
{
|
||||||
|
ItemType: "/Lotus/Types/Items/MiscItems/InstantSalvageRepairItem",
|
||||||
|
ItemCount: -1
|
||||||
|
}
|
||||||
|
];
|
||||||
|
addMiscItems(inventory, inventoryChanges.MiscItems);
|
||||||
|
await inventory.save();
|
||||||
|
res.json({
|
||||||
|
inventoryChanges: inventoryChanges
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
logger.debug(`data provided to ${req.path}: ${String(req.body)}`);
|
||||||
throw new Error(`unhandled guildTech request`);
|
throw new Error(`unhandled guildTech request`);
|
||||||
@ -359,7 +388,7 @@ type TGuildTechRequest =
|
|||||||
| IGuildTechContributeRequest;
|
| IGuildTechContributeRequest;
|
||||||
|
|
||||||
interface IGuildTechBasicRequest {
|
interface IGuildTechBasicRequest {
|
||||||
Action: "Start" | "Fabricate" | "Pause" | "Unpause" | "Cancel" | "Rush";
|
Action: "Start" | "Fabricate" | "Pause" | "Unpause" | "Cancel" | "Rush" | "InstantFinish";
|
||||||
Mode: "Guild" | "Personal";
|
Mode: "Guild" | "Personal";
|
||||||
RecipeType: string;
|
RecipeType: string;
|
||||||
TechProductCategory?: string;
|
TechProductCategory?: string;
|
||||||
@ -380,6 +409,12 @@ interface IGuildTechContributeRequest {
|
|||||||
VaultMiscItems: IMiscItem[];
|
VaultMiscItems: IMiscItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const getSalvageCategory = (
|
||||||
|
category: "CrewShipWeapons" | "CrewShipWeaponSkins"
|
||||||
|
): "CrewShipSalvagedWeapons" | "CrewShipSalvagedWeaponSkins" => {
|
||||||
|
return category == "CrewShipWeapons" ? "CrewShipSalvagedWeapons" : "CrewShipSalvagedWeaponSkins";
|
||||||
|
};
|
||||||
|
|
||||||
const claimSalvagedComponent = (inventory: TInventoryDatabaseDocument, itemId: string): IInventoryChanges => {
|
const claimSalvagedComponent = (inventory: TInventoryDatabaseDocument, itemId: string): IInventoryChanges => {
|
||||||
// delete personal tech project
|
// delete personal tech project
|
||||||
const personalTechProjectIndex = inventory.PersonalTechProjects.findIndex(x => x.CategoryItemId?.equals(itemId));
|
const personalTechProjectIndex = inventory.PersonalTechProjects.findIndex(x => x.CategoryItemId?.equals(itemId));
|
||||||
@ -387,11 +422,19 @@ const claimSalvagedComponent = (inventory: TInventoryDatabaseDocument, itemId: s
|
|||||||
inventory.PersonalTechProjects.splice(personalTechProjectIndex, 1);
|
inventory.PersonalTechProjects.splice(personalTechProjectIndex, 1);
|
||||||
|
|
||||||
const category = personalTechProject.ProductCategory! as "CrewShipWeapons" | "CrewShipWeaponSkins";
|
const category = personalTechProject.ProductCategory! as "CrewShipWeapons" | "CrewShipWeaponSkins";
|
||||||
const salvageCategory = category == "CrewShipWeapons" ? "CrewShipSalvagedWeapons" : "CrewShipSalvagedWeaponSkins";
|
return finishComponentRepair(inventory, category, itemId);
|
||||||
|
};
|
||||||
|
|
||||||
|
const finishComponentRepair = (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
category: "CrewShipWeapons" | "CrewShipWeaponSkins",
|
||||||
|
itemId: string
|
||||||
|
): IInventoryChanges => {
|
||||||
|
const salvageCategory = getSalvageCategory(category);
|
||||||
|
|
||||||
// find salved part & delete it
|
// find salved part & delete it
|
||||||
const salvageIndex = inventory[salvageCategory].findIndex(x => x._id.equals(itemId));
|
const salvageIndex = inventory[salvageCategory].findIndex(x => x._id.equals(itemId));
|
||||||
const salvageItem = inventory[category][salvageIndex];
|
const salvageItem = inventory[salvageCategory][salvageIndex];
|
||||||
inventory[salvageCategory].splice(salvageIndex, 1);
|
inventory[salvageCategory].splice(salvageIndex, 1);
|
||||||
|
|
||||||
// add final item
|
// add final item
|
||||||
|
@ -53,6 +53,9 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
logger.debug("mission report:", missionReport);
|
logger.debug("mission report:", missionReport);
|
||||||
|
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
const firstCompletion = missionReport.SortieId
|
||||||
|
? inventory.CompletedSorties.indexOf(missionReport.SortieId) == -1
|
||||||
|
: false;
|
||||||
const inventoryUpdates = await addMissionInventoryUpdates(inventory, missionReport);
|
const inventoryUpdates = await addMissionInventoryUpdates(inventory, missionReport);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
@ -69,7 +72,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res)
|
|||||||
}
|
}
|
||||||
|
|
||||||
const { MissionRewards, inventoryChanges, credits, AffiliationMods, SyndicateXPItemReward } =
|
const { MissionRewards, inventoryChanges, credits, AffiliationMods, SyndicateXPItemReward } =
|
||||||
await addMissionRewards(inventory, missionReport);
|
await addMissionRewards(inventory, missionReport, firstCompletion);
|
||||||
|
|
||||||
await inventory.save();
|
await inventory.save();
|
||||||
const inventoryResponse = await getInventoryResponse(inventory, true);
|
const inventoryResponse = await getInventoryResponse(inventory, true);
|
||||||
|
@ -17,7 +17,7 @@ import { getDefaultUpgrades } from "@/src/services/itemDataService";
|
|||||||
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper";
|
||||||
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { getRandomInt } from "@/src/services/rngService";
|
import { getRandomInt } from "@/src/services/rngService";
|
||||||
import { ExportSentinels } from "warframe-public-export-plus";
|
import { ExportSentinels, IDefaultUpgrade } from "warframe-public-export-plus";
|
||||||
import { Status } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { Status } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
interface IModularCraftRequest {
|
interface IModularCraftRequest {
|
||||||
@ -34,10 +34,8 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
|
|||||||
const category = modularWeaponTypes[data.WeaponType];
|
const category = modularWeaponTypes[data.WeaponType];
|
||||||
const inventory = await getInventory(accountId);
|
const inventory = await getInventory(accountId);
|
||||||
|
|
||||||
const defaultUpgrades = getDefaultUpgrades(data.Parts);
|
let defaultUpgrades: IDefaultUpgrade[] | undefined;
|
||||||
const defaultOverwrites: Partial<IEquipmentDatabase> = {
|
const defaultOverwrites: Partial<IEquipmentDatabase> = {};
|
||||||
Configs: applyDefaultUpgrades(inventory, defaultUpgrades)
|
|
||||||
};
|
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
if (category == "KubrowPets") {
|
if (category == "KubrowPets") {
|
||||||
const traits = {
|
const traits = {
|
||||||
@ -129,10 +127,17 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res)
|
|||||||
// Only save mutagen & antigen in the ModularParts.
|
// Only save mutagen & antigen in the ModularParts.
|
||||||
defaultOverwrites.ModularParts = [data.Parts[1], data.Parts[2]];
|
defaultOverwrites.ModularParts = [data.Parts[1], data.Parts[2]];
|
||||||
|
|
||||||
for (const specialItem of ExportSentinels[data.WeaponType].exalted!) {
|
const meta = ExportSentinels[data.WeaponType];
|
||||||
|
|
||||||
|
for (const specialItem of meta.exalted!) {
|
||||||
addSpecialItem(inventory, specialItem, inventoryChanges);
|
addSpecialItem(inventory, specialItem, inventoryChanges);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
defaultUpgrades = meta.defaultUpgrades;
|
||||||
|
} else {
|
||||||
|
defaultUpgrades = getDefaultUpgrades(data.Parts);
|
||||||
}
|
}
|
||||||
|
defaultOverwrites.Configs = applyDefaultUpgrades(inventory, defaultUpgrades);
|
||||||
addEquipment(inventory, category, data.WeaponType, data.Parts, inventoryChanges, defaultOverwrites);
|
addEquipment(inventory, category, data.WeaponType, data.Parts, inventoryChanges, defaultOverwrites);
|
||||||
combineInventoryChanges(inventoryChanges, occupySlot(inventory, productCategoryToInventoryBin(category)!, false));
|
combineInventoryChanges(inventoryChanges, occupySlot(inventory, productCategoryToInventoryBin(category)!, false));
|
||||||
if (defaultUpgrades) {
|
if (defaultUpgrades) {
|
||||||
|
21
src/controllers/api/removeIgnoredUserController.ts
Normal file
21
src/controllers/api/removeIgnoredUserController.ts
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
import { getJSONfromString } from "@/src/helpers/stringHelpers";
|
||||||
|
import { Account, Ignore } from "@/src/models/loginModel";
|
||||||
|
import { getAccountForRequest } from "@/src/services/loginService";
|
||||||
|
import { RequestHandler } from "express";
|
||||||
|
|
||||||
|
export const removeIgnoredUserController: RequestHandler = async (req, res) => {
|
||||||
|
const accountId = await getAccountForRequest(req);
|
||||||
|
const data = getJSONfromString<IRemoveIgnoredUserRequest>(String(req.body));
|
||||||
|
const ignoreeAccount = await Account.findOne(
|
||||||
|
{ DisplayName: data.playerName.substring(0, data.playerName.length - 1) },
|
||||||
|
"_id"
|
||||||
|
);
|
||||||
|
if (ignoreeAccount) {
|
||||||
|
await Ignore.deleteOne({ ignorer: accountId, ignoree: ignoreeAccount._id });
|
||||||
|
}
|
||||||
|
res.end();
|
||||||
|
};
|
||||||
|
|
||||||
|
interface IRemoveIgnoredUserRequest {
|
||||||
|
playerName: string;
|
||||||
|
}
|
@ -1,6 +1,6 @@
|
|||||||
import { RequestHandler } from "express";
|
import { RequestHandler } from "express";
|
||||||
import { getAccountIdForRequest } from "@/src/services/loginService";
|
import { getAccountIdForRequest } from "@/src/services/loginService";
|
||||||
import { Account } from "@/src/models/loginModel";
|
import { Account, Ignore } from "@/src/models/loginModel";
|
||||||
import { Inbox } from "@/src/models/inboxModel";
|
import { Inbox } from "@/src/models/inboxModel";
|
||||||
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
import { Inventory } from "@/src/models/inventoryModels/inventoryModel";
|
||||||
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
import { Loadout } from "@/src/models/inventoryModels/loadoutModel";
|
||||||
@ -23,6 +23,8 @@ export const deleteAccountController: RequestHandler = async (req, res) => {
|
|||||||
await Promise.all([
|
await Promise.all([
|
||||||
Account.deleteOne({ _id: accountId }),
|
Account.deleteOne({ _id: accountId }),
|
||||||
GuildMember.deleteMany({ accountId: accountId }),
|
GuildMember.deleteMany({ accountId: accountId }),
|
||||||
|
Ignore.deleteMany({ ignorer: accountId }),
|
||||||
|
Ignore.deleteMany({ ignoree: accountId }),
|
||||||
Inbox.deleteMany({ ownerId: accountId }),
|
Inbox.deleteMany({ ownerId: accountId }),
|
||||||
Inventory.deleteOne({ accountOwnerId: accountId }),
|
Inventory.deleteOne({ accountOwnerId: accountId }),
|
||||||
Leaderboard.deleteMany({ ownerId: accountId }),
|
Leaderboard.deleteMany({ ownerId: accountId }),
|
||||||
|
@ -39,10 +39,9 @@ import {
|
|||||||
ILoreFragmentScan,
|
ILoreFragmentScan,
|
||||||
IEvolutionProgress,
|
IEvolutionProgress,
|
||||||
IEndlessXpProgress,
|
IEndlessXpProgress,
|
||||||
ICrewShipPortGuns,
|
|
||||||
ICrewShipCustomization,
|
ICrewShipCustomization,
|
||||||
ICrewShipWeapon,
|
ICrewShipWeapon,
|
||||||
ICrewShipPilotWeapon,
|
ICrewShipWeaponEmplacements,
|
||||||
IShipExterior,
|
IShipExterior,
|
||||||
IHelminthFoodRecord,
|
IHelminthFoodRecord,
|
||||||
ICrewShipMembersDatabase,
|
ICrewShipMembersDatabase,
|
||||||
@ -88,7 +87,15 @@ import {
|
|||||||
IPersonalTechProjectDatabase,
|
IPersonalTechProjectDatabase,
|
||||||
IPersonalTechProjectClient,
|
IPersonalTechProjectClient,
|
||||||
ILastSortieRewardDatabase,
|
ILastSortieRewardDatabase,
|
||||||
ILastSortieRewardClient
|
ILastSortieRewardClient,
|
||||||
|
ICrewMemberSkill,
|
||||||
|
ICrewMemberSkillEfficiency,
|
||||||
|
ICrewMemberDatabase,
|
||||||
|
ICrewMemberClient,
|
||||||
|
ISortieRewardAttenuation,
|
||||||
|
IInvasionProgressDatabase,
|
||||||
|
IInvasionProgressClient,
|
||||||
|
IAccolades
|
||||||
} from "../../types/inventoryTypes/inventoryTypes";
|
} from "../../types/inventoryTypes/inventoryTypes";
|
||||||
import { IOid } from "../../types/commonTypes";
|
import { IOid } from "../../types/commonTypes";
|
||||||
import {
|
import {
|
||||||
@ -102,7 +109,7 @@ import {
|
|||||||
IEquipmentClient
|
IEquipmentClient
|
||||||
} from "@/src/types/inventoryTypes/commonInventoryTypes";
|
} from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
import { toMongoDate, toOid } from "@/src/helpers/inventoryHelpers";
|
||||||
import { EquipmentSelectionSchema } from "./loadoutModel";
|
import { EquipmentSelectionSchema, oidSchema } from "./loadoutModel";
|
||||||
|
|
||||||
export const typeCountSchema = new Schema<ITypeCount>({ ItemType: String, ItemCount: Number }, { _id: false });
|
export const typeCountSchema = new Schema<ITypeCount>({ ItemType: String, ItemCount: Number }, { _id: false });
|
||||||
|
|
||||||
@ -294,6 +301,55 @@ upgradeSchema.set("toJSON", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const crewMemberSkillSchema = new Schema<ICrewMemberSkill>(
|
||||||
|
{
|
||||||
|
Assigned: Number
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const crewMemberSkillEfficiencySchema = new Schema<ICrewMemberSkillEfficiency>(
|
||||||
|
{
|
||||||
|
PILOTING: crewMemberSkillSchema,
|
||||||
|
GUNNERY: crewMemberSkillSchema,
|
||||||
|
ENGINEERING: crewMemberSkillSchema,
|
||||||
|
COMBAT: crewMemberSkillSchema,
|
||||||
|
SURVIVABILITY: crewMemberSkillSchema
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
const crewMemberSchema = new Schema<ICrewMemberDatabase>(
|
||||||
|
{
|
||||||
|
ItemType: { type: String, required: true },
|
||||||
|
NemesisFingerprint: { type: BigInt, default: 0n },
|
||||||
|
Seed: { type: BigInt, default: 0n },
|
||||||
|
AssignedRole: Number,
|
||||||
|
SkillEfficiency: crewMemberSkillEfficiencySchema,
|
||||||
|
WeaponConfigIdx: Number,
|
||||||
|
WeaponId: { type: Schema.Types.ObjectId, default: "000000000000000000000000" },
|
||||||
|
XP: { type: Number, default: 0 },
|
||||||
|
PowersuitType: { type: String, required: true },
|
||||||
|
Configs: [ItemConfigSchema],
|
||||||
|
SecondInCommand: { type: Boolean, default: false }
|
||||||
|
},
|
||||||
|
{ id: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
crewMemberSchema.set("toJSON", {
|
||||||
|
virtuals: true,
|
||||||
|
transform(_doc, obj) {
|
||||||
|
const db = obj as ICrewMemberDatabase;
|
||||||
|
const client = obj as ICrewMemberClient;
|
||||||
|
|
||||||
|
client.WeaponId = toOid(db.WeaponId);
|
||||||
|
client.ItemId = toOid(db._id);
|
||||||
|
|
||||||
|
delete obj._id;
|
||||||
|
delete obj.__v;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const slotsBinSchema = new Schema<ISlots>(
|
const slotsBinSchema = new Schema<ISlots>(
|
||||||
{
|
{
|
||||||
Slots: Number,
|
Slots: Number,
|
||||||
@ -631,6 +687,27 @@ questKeysSchema.set("toJSON", {
|
|||||||
|
|
||||||
export const fusionTreasuresSchema = new Schema<IFusionTreasure>().add(typeCountSchema).add({ Sockets: Number });
|
export const fusionTreasuresSchema = new Schema<IFusionTreasure>().add(typeCountSchema).add({ Sockets: Number });
|
||||||
|
|
||||||
|
const invasionProgressSchema = new Schema<IInvasionProgressDatabase>(
|
||||||
|
{
|
||||||
|
invasionId: Schema.Types.ObjectId,
|
||||||
|
Delta: Number,
|
||||||
|
AttackerScore: Number,
|
||||||
|
DefenderScore: Number
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
|
invasionProgressSchema.set("toJSON", {
|
||||||
|
transform(_doc, obj) {
|
||||||
|
const db = obj as IInvasionProgressDatabase;
|
||||||
|
const client = obj as IInvasionProgressClient;
|
||||||
|
|
||||||
|
client._id = toOid(db.invasionId);
|
||||||
|
delete obj.invasionId;
|
||||||
|
delete obj.__v;
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
const spectreLoadoutsSchema = new Schema<ISpectreLoadout>(
|
const spectreLoadoutsSchema = new Schema<ISpectreLoadout>(
|
||||||
{
|
{
|
||||||
ItemType: String,
|
ItemType: String,
|
||||||
@ -719,25 +796,23 @@ const endlessXpProgressSchema = new Schema<IEndlessXpProgress>(
|
|||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
const crewShipPilotWeaponSchema = new Schema<ICrewShipPilotWeapon>(
|
const crewShipWeaponEmplacementsSchema = new Schema<ICrewShipWeaponEmplacements>(
|
||||||
{
|
{
|
||||||
PRIMARY_A: EquipmentSelectionSchema,
|
PRIMARY_A: EquipmentSelectionSchema,
|
||||||
SECONDARY_A: EquipmentSelectionSchema
|
PRIMARY_B: EquipmentSelectionSchema,
|
||||||
},
|
SECONDARY_A: EquipmentSelectionSchema,
|
||||||
{ _id: false }
|
SECONDARY_B: EquipmentSelectionSchema
|
||||||
);
|
|
||||||
|
|
||||||
const crewShipPortGunsSchema = new Schema<ICrewShipPortGuns>(
|
|
||||||
{
|
|
||||||
PRIMARY_A: EquipmentSelectionSchema
|
|
||||||
},
|
},
|
||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
|
|
||||||
const crewShipWeaponSchema = new Schema<ICrewShipWeapon>(
|
const crewShipWeaponSchema = new Schema<ICrewShipWeapon>(
|
||||||
{
|
{
|
||||||
PILOT: crewShipPilotWeaponSchema,
|
PILOT: crewShipWeaponEmplacementsSchema,
|
||||||
PORT_GUNS: crewShipPortGunsSchema
|
PORT_GUNS: crewShipWeaponEmplacementsSchema,
|
||||||
|
STARBOARD_GUNS: crewShipWeaponEmplacementsSchema,
|
||||||
|
ARTILLERY: crewShipWeaponEmplacementsSchema,
|
||||||
|
SCANNER: crewShipWeaponEmplacementsSchema
|
||||||
},
|
},
|
||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
@ -761,7 +836,7 @@ const crewShipCustomizationSchema = new Schema<ICrewShipCustomization>(
|
|||||||
const crewShipMemberSchema = new Schema<ICrewShipMemberDatabase>(
|
const crewShipMemberSchema = new Schema<ICrewShipMemberDatabase>(
|
||||||
{
|
{
|
||||||
ItemId: { type: Schema.Types.ObjectId, required: false },
|
ItemId: { type: Schema.Types.ObjectId, required: false },
|
||||||
NemesisFingerprint: { type: Number, required: false }
|
NemesisFingerprint: { type: BigInt, required: false }
|
||||||
},
|
},
|
||||||
{ _id: false }
|
{ _id: false }
|
||||||
);
|
);
|
||||||
@ -985,6 +1060,13 @@ pendingRecipeSchema.set("toJSON", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const accoladesSchema = new Schema<IAccolades>(
|
||||||
|
{
|
||||||
|
Heirloom: Boolean
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
const infestedFoundrySchema = new Schema<IInfestedFoundryDatabase>(
|
const infestedFoundrySchema = new Schema<IInfestedFoundryDatabase>(
|
||||||
{
|
{
|
||||||
Name: String,
|
Name: String,
|
||||||
@ -1226,6 +1308,14 @@ lastSortieRewardSchema.set("toJSON", {
|
|||||||
}
|
}
|
||||||
});
|
});
|
||||||
|
|
||||||
|
const sortieRewardAttenutationSchema = new Schema<ISortieRewardAttenuation>(
|
||||||
|
{
|
||||||
|
Tag: String,
|
||||||
|
Atten: Number
|
||||||
|
},
|
||||||
|
{ _id: false }
|
||||||
|
);
|
||||||
|
|
||||||
const lockedWeaponGroupSchema = new Schema<ILockedWeaponGroupDatabase>(
|
const lockedWeaponGroupSchema = new Schema<ILockedWeaponGroupDatabase>(
|
||||||
{
|
{
|
||||||
s: Schema.Types.ObjectId,
|
s: Schema.Types.ObjectId,
|
||||||
@ -1363,7 +1453,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
CrewShipSalvagedWeaponSkins: [upgradeSchema],
|
CrewShipSalvagedWeaponSkins: [upgradeSchema],
|
||||||
|
|
||||||
//RailJack Crew
|
//RailJack Crew
|
||||||
CrewMembers: [Schema.Types.Mixed],
|
CrewMembers: [crewMemberSchema],
|
||||||
|
|
||||||
//Complete Mission\Quests
|
//Complete Mission\Quests
|
||||||
Missions: [missionSchema],
|
Missions: [missionSchema],
|
||||||
@ -1384,6 +1474,16 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
//Mastery Rank next availability
|
//Mastery Rank next availability
|
||||||
TrainingDate: { type: Date, default: new Date(0) },
|
TrainingDate: { type: Date, default: new Date(0) },
|
||||||
|
|
||||||
|
//Accolades
|
||||||
|
Staff: Boolean,
|
||||||
|
Founder: Number,
|
||||||
|
Guide: Number,
|
||||||
|
Moderator: Boolean,
|
||||||
|
Partner: Boolean,
|
||||||
|
Accolades: accoladesSchema,
|
||||||
|
//Not an accolade but unlocks an extra chat
|
||||||
|
Counselor: Boolean,
|
||||||
|
|
||||||
//you saw last played Region when you opened the star map
|
//you saw last played Region when you opened the star map
|
||||||
LastRegionPlayed: String,
|
LastRegionPlayed: String,
|
||||||
|
|
||||||
@ -1423,7 +1523,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
|
|
||||||
SentientSpawnChanceBoosters: Schema.Types.Mixed,
|
SentientSpawnChanceBoosters: Schema.Types.Mixed,
|
||||||
|
|
||||||
QualifyingInvasions: [Schema.Types.Mixed],
|
QualifyingInvasions: [invasionProgressSchema],
|
||||||
FactionScores: [Number],
|
FactionScores: [Number],
|
||||||
|
|
||||||
// https://warframe.fandom.com/wiki/Specter_(Tenno)
|
// https://warframe.fandom.com/wiki/Specter_(Tenno)
|
||||||
@ -1445,6 +1545,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
CompletedSorties: [String],
|
CompletedSorties: [String],
|
||||||
LastSortieReward: { type: [lastSortieRewardSchema], default: undefined },
|
LastSortieReward: { type: [lastSortieRewardSchema], default: undefined },
|
||||||
LastLiteSortieReward: { type: [lastSortieRewardSchema], default: undefined },
|
LastLiteSortieReward: { type: [lastSortieRewardSchema], default: undefined },
|
||||||
|
SortieRewardAttenuation: { type: [sortieRewardAttenutationSchema], default: undefined },
|
||||||
|
|
||||||
// Resource Extractor Drones
|
// Resource Extractor Drones
|
||||||
Drones: [droneSchema],
|
Drones: [droneSchema],
|
||||||
@ -1538,7 +1639,7 @@ const inventorySchema = new Schema<IInventoryDatabase, InventoryDocumentProps>(
|
|||||||
HasContributedToDojo: Boolean,
|
HasContributedToDojo: Boolean,
|
||||||
HWIDProtectEnabled: Boolean,
|
HWIDProtectEnabled: Boolean,
|
||||||
LoadOutPresets: { type: Schema.Types.ObjectId, ref: "Loadout" },
|
LoadOutPresets: { type: Schema.Types.ObjectId, ref: "Loadout" },
|
||||||
CurrentLoadOutIds: [Schema.Types.Mixed],
|
CurrentLoadOutIds: [oidSchema],
|
||||||
RandomUpgradesIdentified: Number,
|
RandomUpgradesIdentified: Number,
|
||||||
BountyScore: Number,
|
BountyScore: Number,
|
||||||
ChallengeInstanceStates: [Schema.Types.Mixed],
|
ChallengeInstanceStates: [Schema.Types.Mixed],
|
||||||
@ -1645,6 +1746,7 @@ export type InventoryDocumentProps = {
|
|||||||
CrewShipWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
|
CrewShipWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
|
||||||
CrewShipSalvagedWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
|
CrewShipSalvagedWeaponSkins: Types.DocumentArray<IUpgradeDatabase>;
|
||||||
PersonalTechProjects: Types.DocumentArray<IPersonalTechProjectDatabase>;
|
PersonalTechProjects: Types.DocumentArray<IPersonalTechProjectDatabase>;
|
||||||
|
CrewMembers: Types.DocumentArray<ICrewMemberDatabase>;
|
||||||
} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
|
} & { [K in TEquipmentKey]: Types.DocumentArray<IEquipmentDatabase> };
|
||||||
|
|
||||||
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
||||||
|
@ -3,7 +3,7 @@ import { IEquipmentSelection } from "@/src/types/inventoryTypes/commonInventoryT
|
|||||||
import { ILoadoutConfigDatabase, ILoadoutDatabase } from "@/src/types/saveLoadoutTypes";
|
import { ILoadoutConfigDatabase, ILoadoutDatabase } from "@/src/types/saveLoadoutTypes";
|
||||||
import { Document, Model, Schema, Types, model } from "mongoose";
|
import { Document, Model, Schema, Types, model } from "mongoose";
|
||||||
|
|
||||||
const oidSchema = new Schema<IOid>(
|
export const oidSchema = new Schema<IOid>(
|
||||||
{
|
{
|
||||||
$oid: String
|
$oid: String
|
||||||
},
|
},
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { IDatabaseAccountJson } from "@/src/types/loginTypes";
|
import { IDatabaseAccountJson, IIgnore } from "@/src/types/loginTypes";
|
||||||
import { model, Schema, SchemaOptions } from "mongoose";
|
import { model, Schema, SchemaOptions } from "mongoose";
|
||||||
|
|
||||||
const opts = {
|
const opts = {
|
||||||
@ -37,3 +37,13 @@ databaseAccountSchema.set("toJSON", {
|
|||||||
});
|
});
|
||||||
|
|
||||||
export const Account = model<IDatabaseAccountJson>("Account", databaseAccountSchema);
|
export const Account = model<IDatabaseAccountJson>("Account", databaseAccountSchema);
|
||||||
|
|
||||||
|
const ignoreSchema = new Schema<IIgnore>({
|
||||||
|
ignorer: Schema.Types.ObjectId,
|
||||||
|
ignoree: Schema.Types.ObjectId
|
||||||
|
});
|
||||||
|
|
||||||
|
ignoreSchema.index({ ignorer: 1 });
|
||||||
|
ignoreSchema.index({ ignorer: 1, ignoree: 1 }, { unique: true });
|
||||||
|
|
||||||
|
export const Ignore = model<IIgnore>("Ignore", ignoreSchema);
|
||||||
|
@ -4,6 +4,7 @@ import { abortDojoComponentController } from "@/src/controllers/api/abortDojoCom
|
|||||||
import { abortDojoComponentDestructionController } from "@/src/controllers/api/abortDojoComponentDestructionController";
|
import { abortDojoComponentDestructionController } from "@/src/controllers/api/abortDojoComponentDestructionController";
|
||||||
import { activateRandomModController } from "@/src/controllers/api/activateRandomModController";
|
import { activateRandomModController } from "@/src/controllers/api/activateRandomModController";
|
||||||
import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
|
import { addFriendImageController } from "@/src/controllers/api/addFriendImageController";
|
||||||
|
import { addIgnoredUserController } from "@/src/controllers/api/addIgnoredUserController";
|
||||||
import { addToAllianceController } from "@/src/controllers/api/addToAllianceController";
|
import { addToAllianceController } from "@/src/controllers/api/addToAllianceController";
|
||||||
import { addToGuildController } from "@/src/controllers/api/addToGuildController";
|
import { addToGuildController } from "@/src/controllers/api/addToGuildController";
|
||||||
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
|
import { arcaneCommonController } from "@/src/controllers/api/arcaneCommonController";
|
||||||
@ -27,6 +28,7 @@ import { contributeToVaultController } from "@/src/controllers/api/contributeToV
|
|||||||
import { createAllianceController } from "@/src/controllers/api/createAllianceController";
|
import { createAllianceController } from "@/src/controllers/api/createAllianceController";
|
||||||
import { createGuildController } from "@/src/controllers/api/createGuildController";
|
import { createGuildController } from "@/src/controllers/api/createGuildController";
|
||||||
import { creditsController } from "@/src/controllers/api/creditsController";
|
import { creditsController } from "@/src/controllers/api/creditsController";
|
||||||
|
import { crewMembersController } from "@/src/controllers/api/crewMembersController";
|
||||||
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
|
import { crewShipIdentifySalvageController } from "@/src/controllers/api/crewShipIdentifySalvageController";
|
||||||
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
import { customizeGuildRanksController } from "@/src/controllers/api/customizeGuildRanksController";
|
||||||
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
|
import { customObstacleCourseLeaderboardController } from "@/src/controllers/api/customObstacleCourseLeaderboardController";
|
||||||
@ -97,6 +99,7 @@ import { redeemPromoCodeController } from "@/src/controllers/api/redeemPromoCode
|
|||||||
import { releasePetController } from "@/src/controllers/api/releasePetController";
|
import { releasePetController } from "@/src/controllers/api/releasePetController";
|
||||||
import { removeFromAllianceController } from "@/src/controllers/api/removeFromAllianceController";
|
import { removeFromAllianceController } from "@/src/controllers/api/removeFromAllianceController";
|
||||||
import { removeFromGuildController } from "@/src/controllers/api/removeFromGuildController";
|
import { removeFromGuildController } from "@/src/controllers/api/removeFromGuildController";
|
||||||
|
import { removeIgnoredUserController } from "@/src/controllers/api/removeIgnoredUserController";
|
||||||
import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController";
|
import { rerollRandomModController } from "@/src/controllers/api/rerollRandomModController";
|
||||||
import { retrievePetFromStasisController } from "@/src/controllers/api/retrievePetFromStasisController";
|
import { retrievePetFromStasisController } from "@/src/controllers/api/retrievePetFromStasisController";
|
||||||
import { saveDialogueController } from "@/src/controllers/api/saveDialogueController";
|
import { saveDialogueController } from "@/src/controllers/api/saveDialogueController";
|
||||||
@ -202,6 +205,7 @@ apiRouter.get("/updateSession.php", updateSessionGetController);
|
|||||||
apiRouter.post("/abortDojoComponent.php", abortDojoComponentController);
|
apiRouter.post("/abortDojoComponent.php", abortDojoComponentController);
|
||||||
apiRouter.post("/activateRandomMod.php", activateRandomModController);
|
apiRouter.post("/activateRandomMod.php", activateRandomModController);
|
||||||
apiRouter.post("/addFriendImage.php", addFriendImageController);
|
apiRouter.post("/addFriendImage.php", addFriendImageController);
|
||||||
|
apiRouter.post("/addIgnoredUser.php", addIgnoredUserController);
|
||||||
apiRouter.post("/addToAlliance.php", addToAllianceController);
|
apiRouter.post("/addToAlliance.php", addToAllianceController);
|
||||||
apiRouter.post("/addToGuild.php", addToGuildController);
|
apiRouter.post("/addToGuild.php", addToGuildController);
|
||||||
apiRouter.post("/arcaneCommon.php", arcaneCommonController);
|
apiRouter.post("/arcaneCommon.php", arcaneCommonController);
|
||||||
@ -219,6 +223,7 @@ apiRouter.post("/contributeToDojoComponent.php", contributeToDojoComponentContro
|
|||||||
apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
apiRouter.post("/contributeToVault.php", contributeToVaultController);
|
||||||
apiRouter.post("/createAlliance.php", createAllianceController);
|
apiRouter.post("/createAlliance.php", createAllianceController);
|
||||||
apiRouter.post("/createGuild.php", createGuildController);
|
apiRouter.post("/createGuild.php", createGuildController);
|
||||||
|
apiRouter.post("/crewMembers.php", crewMembersController);
|
||||||
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
|
apiRouter.post("/crewShipIdentifySalvage.php", crewShipIdentifySalvageController);
|
||||||
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
apiRouter.post("/customizeGuildRanks.php", customizeGuildRanksController);
|
||||||
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
apiRouter.post("/customObstacleCourseLeaderboard.php", customObstacleCourseLeaderboardController);
|
||||||
@ -266,6 +271,7 @@ apiRouter.post("/purchase.php", purchaseController);
|
|||||||
apiRouter.post("/redeemPromoCode.php", redeemPromoCodeController);
|
apiRouter.post("/redeemPromoCode.php", redeemPromoCodeController);
|
||||||
apiRouter.post("/releasePet.php", releasePetController);
|
apiRouter.post("/releasePet.php", releasePetController);
|
||||||
apiRouter.post("/removeFromGuild.php", removeFromGuildController);
|
apiRouter.post("/removeFromGuild.php", removeFromGuildController);
|
||||||
|
apiRouter.post("/removeIgnoredUser.php", removeIgnoredUserController);
|
||||||
apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
|
apiRouter.post("/rerollRandomMod.php", rerollRandomModController);
|
||||||
apiRouter.post("/retrievePetFromStasis.php", retrievePetFromStasisController);
|
apiRouter.post("/retrievePetFromStasis.php", retrievePetFromStasisController);
|
||||||
apiRouter.post("/saveDialogue.php", saveDialogueController);
|
apiRouter.post("/saveDialogue.php", saveDialogueController);
|
||||||
|
@ -59,6 +59,7 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
|
|||||||
|
|
||||||
const members: IGuildMemberClient[] = [];
|
const members: IGuildMemberClient[] = [];
|
||||||
let missingEntry = true;
|
let missingEntry = true;
|
||||||
|
const dataFillInPromises: Promise<void>[] = [];
|
||||||
for (const guildMember of guildMembers) {
|
for (const guildMember of guildMembers) {
|
||||||
const member: IGuildMemberClient = {
|
const member: IGuildMemberClient = {
|
||||||
_id: toOid(guildMember.accountId),
|
_id: toOid(guildMember.accountId),
|
||||||
@ -70,8 +71,12 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
|
|||||||
if (guildMember.accountId.equals(accountId)) {
|
if (guildMember.accountId.equals(accountId)) {
|
||||||
missingEntry = false;
|
missingEntry = false;
|
||||||
} else {
|
} else {
|
||||||
|
dataFillInPromises.push(
|
||||||
|
(async (): Promise<void> => {
|
||||||
member.DisplayName = (await Account.findById(guildMember.accountId, "DisplayName"))!.DisplayName;
|
member.DisplayName = (await Account.findById(guildMember.accountId, "DisplayName"))!.DisplayName;
|
||||||
await fillInInventoryDataForGuildMember(member);
|
})()
|
||||||
|
);
|
||||||
|
dataFillInPromises.push(fillInInventoryDataForGuildMember(member));
|
||||||
}
|
}
|
||||||
members.push(member);
|
members.push(member);
|
||||||
}
|
}
|
||||||
@ -90,6 +95,8 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
await Promise.all(dataFillInPromises);
|
||||||
|
|
||||||
return {
|
return {
|
||||||
_id: toOid(guild._id),
|
_id: toOid(guild._id),
|
||||||
Name: guild.Name,
|
Name: guild.Name,
|
||||||
|
@ -104,18 +104,18 @@ const replaceSlots = (db: ISlots, client: ISlots): void => {
|
|||||||
db.Slots = client.Slots;
|
db.Slots = client.Slots;
|
||||||
};
|
};
|
||||||
|
|
||||||
const convertCrewShipMember = (client: ICrewShipMemberClient): ICrewShipMemberDatabase => {
|
export const importCrewMemberId = (crewMemberId: ICrewShipMemberClient): ICrewShipMemberDatabase => {
|
||||||
return {
|
if (crewMemberId.ItemId) {
|
||||||
...client,
|
return { ItemId: new Types.ObjectId(crewMemberId.ItemId.$oid) };
|
||||||
ItemId: client.ItemId ? new Types.ObjectId(client.ItemId.$oid) : undefined
|
}
|
||||||
};
|
return { NemesisFingerprint: BigInt(crewMemberId.NemesisFingerprint ?? 0) };
|
||||||
};
|
};
|
||||||
|
|
||||||
const convertCrewShipMembers = (client: ICrewShipMembersClient): ICrewShipMembersDatabase => {
|
const convertCrewShipMembers = (client: ICrewShipMembersClient): ICrewShipMembersDatabase => {
|
||||||
return {
|
return {
|
||||||
SLOT_A: client.SLOT_A ? convertCrewShipMember(client.SLOT_A) : undefined,
|
SLOT_A: client.SLOT_A ? importCrewMemberId(client.SLOT_A) : undefined,
|
||||||
SLOT_B: client.SLOT_B ? convertCrewShipMember(client.SLOT_B) : undefined,
|
SLOT_B: client.SLOT_B ? importCrewMemberId(client.SLOT_B) : undefined,
|
||||||
SLOT_C: client.SLOT_C ? convertCrewShipMember(client.SLOT_C) : undefined
|
SLOT_C: client.SLOT_C ? importCrewMemberId(client.SLOT_C) : undefined
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -230,17 +230,23 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
replaceSlots(db[key], client[key]);
|
replaceSlots(db[key], client[key]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// boolean
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"UseAdultOperatorLoadout",
|
"UseAdultOperatorLoadout",
|
||||||
"HasOwnedVoidProjectionsPreviously",
|
"HasOwnedVoidProjectionsPreviously",
|
||||||
"ReceivedStartingGear",
|
"ReceivedStartingGear",
|
||||||
"ArchwingEnabled",
|
"ArchwingEnabled",
|
||||||
"PlayedParkourTutorial"
|
"PlayedParkourTutorial",
|
||||||
|
"Staff",
|
||||||
|
"Moderator",
|
||||||
|
"Partner",
|
||||||
|
"Counselor"
|
||||||
] as const) {
|
] as const) {
|
||||||
if (client[key] !== undefined) {
|
if (client[key] !== undefined) {
|
||||||
db[key] = client[key];
|
db[key] = client[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// number
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"PlayerLevel",
|
"PlayerLevel",
|
||||||
"RegularCredits",
|
"RegularCredits",
|
||||||
@ -250,12 +256,15 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
"PrimeTokens",
|
"PrimeTokens",
|
||||||
"TradesRemaining",
|
"TradesRemaining",
|
||||||
"GiftsRemaining",
|
"GiftsRemaining",
|
||||||
"ChallengesFixVersion"
|
"ChallengesFixVersion",
|
||||||
|
"Founder",
|
||||||
|
"Guide"
|
||||||
] as const) {
|
] as const) {
|
||||||
if (client[key] !== undefined) {
|
if (client[key] !== undefined) {
|
||||||
db[key] = client[key];
|
db[key] = client[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// string
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"ThemeStyle",
|
"ThemeStyle",
|
||||||
"ThemeBackground",
|
"ThemeBackground",
|
||||||
@ -270,6 +279,7 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
db[key] = client[key];
|
db[key] = client[key];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
// string[]
|
||||||
for (const key of [
|
for (const key of [
|
||||||
"EquippedGear",
|
"EquippedGear",
|
||||||
"EquippedEmotes",
|
"EquippedEmotes",
|
||||||
@ -380,6 +390,9 @@ export const importInventory = (db: TInventoryDatabaseDocument, client: Partial<
|
|||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
if (client.Accolades !== undefined) {
|
||||||
|
db.Accolades = client.Accolades;
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
const convertLoadOutConfig = (client: ILoadoutConfigClient): ILoadoutConfigDatabase => {
|
const convertLoadOutConfig = (client: ILoadoutConfigClient): ILoadoutConfigDatabase => {
|
||||||
|
@ -22,7 +22,8 @@ import {
|
|||||||
IDroneClient,
|
IDroneClient,
|
||||||
IUpgradeClient,
|
IUpgradeClient,
|
||||||
TPartialStartingGear,
|
TPartialStartingGear,
|
||||||
ILoreFragmentScan
|
ILoreFragmentScan,
|
||||||
|
ICrewMemberClient
|
||||||
} from "@/src/types/inventoryTypes/inventoryTypes";
|
} from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
|
import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate";
|
||||||
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
|
import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes";
|
||||||
@ -713,6 +714,15 @@ export const addItem = async (
|
|||||||
return {
|
return {
|
||||||
MiscItems: miscItemChanges
|
MiscItems: miscItemChanges
|
||||||
};
|
};
|
||||||
|
} else if (typeName.startsWith("/Lotus/Types/Game/CrewShip/CrewMember/")) {
|
||||||
|
if (!seed) {
|
||||||
|
throw new Error(`Expected crew member to have a seed`);
|
||||||
|
}
|
||||||
|
seed |= 0x33b81en << 32n;
|
||||||
|
return {
|
||||||
|
...addCrewMember(inventory, typeName, seed),
|
||||||
|
...occupySlot(inventory, InventorySlot.CREWMEMBERS, premiumPurchase)
|
||||||
|
};
|
||||||
} else if (typeName == "/Lotus/Types/Game/CrewShip/RailJack/DefaultHarness") {
|
} else if (typeName == "/Lotus/Types/Game/CrewShip/RailJack/DefaultHarness") {
|
||||||
return addCrewShipHarness(inventory, typeName);
|
return addCrewShipHarness(inventory, typeName);
|
||||||
}
|
}
|
||||||
@ -1212,6 +1222,78 @@ const addDrone = (
|
|||||||
return inventoryChanges;
|
return inventoryChanges;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/*const getCrewMemberSkills = (seed: bigint, skillPointsToAssign: number): Record<string, number> => {
|
||||||
|
const rng = new SRng(seed);
|
||||||
|
|
||||||
|
const skills = ["PILOTING", "GUNNERY", "ENGINEERING", "COMBAT", "SURVIVABILITY"];
|
||||||
|
for (let i = 1; i != 5; ++i) {
|
||||||
|
const swapIndex = rng.randomInt(0, i);
|
||||||
|
if (swapIndex != i) {
|
||||||
|
const tmp = skills[i];
|
||||||
|
skills[i] = skills[swapIndex];
|
||||||
|
skills[swapIndex] = tmp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
rng.randomFloat(); // unused afaict
|
||||||
|
|
||||||
|
const skillAssignments = [0, 0, 0, 0, 0];
|
||||||
|
for (let skill = 0; skillPointsToAssign; skill = (skill + 1) % 5) {
|
||||||
|
const maxIncrease = Math.min(5 - skillAssignments[skill], skillPointsToAssign);
|
||||||
|
const increase = rng.randomInt(0, maxIncrease);
|
||||||
|
skillAssignments[skill] += increase;
|
||||||
|
skillPointsToAssign -= increase;
|
||||||
|
}
|
||||||
|
|
||||||
|
skillAssignments.sort((a, b) => b - a);
|
||||||
|
|
||||||
|
const combined: Record<string, number> = {};
|
||||||
|
for (let i = 0; i != 5; ++i) {
|
||||||
|
combined[skills[i]] = skillAssignments[i];
|
||||||
|
}
|
||||||
|
return combined;
|
||||||
|
};*/
|
||||||
|
|
||||||
|
const addCrewMember = (
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
itemType: string,
|
||||||
|
seed: bigint,
|
||||||
|
inventoryChanges: IInventoryChanges = {}
|
||||||
|
): IInventoryChanges => {
|
||||||
|
// SkillEfficiency is additional to the base stats, so we don't need to compute this
|
||||||
|
//const skillPointsToAssign = itemType.endsWith("Strong") ? 12 : itemType.indexOf("Medium") != -1 ? 10 : 8;
|
||||||
|
//const skills = getCrewMemberSkills(seed, skillPointsToAssign);
|
||||||
|
|
||||||
|
// Arbiters = male
|
||||||
|
// CephalonSuda = female
|
||||||
|
// NewLoka = female
|
||||||
|
// Perrin = male
|
||||||
|
// RedVeil = male
|
||||||
|
// SteelMeridian = female
|
||||||
|
const powersuitType =
|
||||||
|
itemType.indexOf("Arbiters") != -1 || itemType.indexOf("Perrin") != -1 || itemType.indexOf("RedVeil") != -1
|
||||||
|
? "/Lotus/Powersuits/NpcPowersuits/CrewMemberMaleSuit"
|
||||||
|
: "/Lotus/Powersuits/NpcPowersuits/CrewMemberFemaleSuit";
|
||||||
|
|
||||||
|
const index =
|
||||||
|
inventory.CrewMembers.push({
|
||||||
|
ItemType: itemType,
|
||||||
|
NemesisFingerprint: 0n,
|
||||||
|
Seed: seed,
|
||||||
|
SkillEfficiency: {
|
||||||
|
PILOTING: { Assigned: 0 },
|
||||||
|
GUNNERY: { Assigned: 0 },
|
||||||
|
ENGINEERING: { Assigned: 0 },
|
||||||
|
COMBAT: { Assigned: 0 },
|
||||||
|
SURVIVABILITY: { Assigned: 0 }
|
||||||
|
},
|
||||||
|
PowersuitType: powersuitType
|
||||||
|
}) - 1;
|
||||||
|
inventoryChanges.CrewMembers ??= [];
|
||||||
|
inventoryChanges.CrewMembers.push(inventory.CrewMembers[index].toJSON<ICrewMemberClient>());
|
||||||
|
return inventoryChanges;
|
||||||
|
};
|
||||||
|
|
||||||
export const addEmailItem = async (
|
export const addEmailItem = async (
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
typeName: string,
|
typeName: string,
|
||||||
|
@ -53,7 +53,7 @@ import conservationAnimals from "@/static/fixed_responses/conservationAnimals.js
|
|||||||
import { getInfNodes } from "@/src/helpers/nemesisHelpers";
|
import { getInfNodes } from "@/src/helpers/nemesisHelpers";
|
||||||
import { Loadout } from "../models/inventoryModels/loadoutModel";
|
import { Loadout } from "../models/inventoryModels/loadoutModel";
|
||||||
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
|
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
|
||||||
import { getWorldState } from "./worldStateService";
|
import { getLiteSortie, getWorldState, idToWeek } from "./worldStateService";
|
||||||
import { config } from "./configService";
|
import { config } from "./configService";
|
||||||
|
|
||||||
const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => {
|
const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => {
|
||||||
@ -71,7 +71,12 @@ const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[]
|
|||||||
return [rewardInfo.rewardTier];
|
return [rewardInfo.rewardTier];
|
||||||
}
|
}
|
||||||
|
|
||||||
const rotationCount = rewardInfo.rewardQualifications?.length || 0;
|
// Aborting a railjack mission should not give any rewards (https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1741)
|
||||||
|
if (rewardInfo.rewardQualifications === undefined) {
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
|
||||||
|
const rotationCount = rewardInfo.rewardQualifications.length || 0;
|
||||||
if (rotationCount === 0) return [0];
|
if (rotationCount === 0) return [0];
|
||||||
|
|
||||||
const rotationPattern =
|
const rotationPattern =
|
||||||
@ -128,11 +133,18 @@ export const addMissionInventoryUpdates = async (
|
|||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Somewhat heuristically detect G3 capture:
|
||||||
|
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1365
|
||||||
|
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1694
|
||||||
|
// - https://onlyg.it/OpenWF/SpaceNinjaServer/issues/1724
|
||||||
if (
|
if (
|
||||||
inventoryUpdates.MissionFailed &&
|
inventoryUpdates.MissionFailed &&
|
||||||
inventoryUpdates.MissionStatus == "GS_FAILURE" &&
|
inventoryUpdates.MissionStatus == "GS_FAILURE" &&
|
||||||
inventoryUpdates.ObjectiveReached &&
|
inventoryUpdates.ObjectiveReached &&
|
||||||
!inventoryUpdates.LockedWeaponGroup
|
!inventoryUpdates.LockedWeaponGroup &&
|
||||||
|
!inventory.LockedWeaponGroup &&
|
||||||
|
!inventoryUpdates.LevelKeyName
|
||||||
) {
|
) {
|
||||||
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
|
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
|
||||||
const config = loadout.NORMAL.id(inventory.CurrentLoadOutIds[0].$oid)!;
|
const config = loadout.NORMAL.id(inventory.CurrentLoadOutIds[0].$oid)!;
|
||||||
@ -407,7 +419,9 @@ export const addMissionInventoryUpdates = async (
|
|||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "SortieId": {
|
case "SortieId": {
|
||||||
|
if (inventory.CompletedSorties.indexOf(value) == -1) {
|
||||||
inventory.CompletedSorties.push(value);
|
inventory.CompletedSorties.push(value);
|
||||||
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "SeasonChallengeCompletions": {
|
case "SeasonChallengeCompletions": {
|
||||||
@ -525,6 +539,26 @@ export const addMissionInventoryUpdates = async (
|
|||||||
inventoryChanges.RegularCredits -= value;
|
inventoryChanges.RegularCredits -= value;
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
case "InvasionProgress": {
|
||||||
|
for (const clientProgress of value) {
|
||||||
|
const dbProgress = inventory.QualifyingInvasions.find(x =>
|
||||||
|
x.invasionId.equals(clientProgress._id.$oid)
|
||||||
|
);
|
||||||
|
if (dbProgress) {
|
||||||
|
dbProgress.Delta += clientProgress.Delta;
|
||||||
|
dbProgress.AttackerScore += clientProgress.AttackerScore;
|
||||||
|
dbProgress.DefenderScore += clientProgress.DefenderScore;
|
||||||
|
} else {
|
||||||
|
inventory.QualifyingInvasions.push({
|
||||||
|
invasionId: new Types.ObjectId(clientProgress._id.$oid),
|
||||||
|
Delta: clientProgress.Delta,
|
||||||
|
AttackerScore: clientProgress.AttackerScore,
|
||||||
|
DefenderScore: clientProgress.DefenderScore
|
||||||
|
});
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
// Equipment XP updates
|
// Equipment XP updates
|
||||||
if (equipmentKeys.includes(key as TEquipmentKey)) {
|
if (equipmentKeys.includes(key as TEquipmentKey)) {
|
||||||
@ -564,7 +598,8 @@ export const addMissionRewards = async (
|
|||||||
RegularCredits: creditDrops,
|
RegularCredits: creditDrops,
|
||||||
VoidTearParticipantsCurrWave: voidTearWave,
|
VoidTearParticipantsCurrWave: voidTearWave,
|
||||||
StrippedItems: strippedItems
|
StrippedItems: strippedItems
|
||||||
}: IMissionInventoryUpdateRequest
|
}: IMissionInventoryUpdateRequest,
|
||||||
|
firstCompletion: boolean
|
||||||
): Promise<AddMissionRewardsReturnType> => {
|
): Promise<AddMissionRewardsReturnType> => {
|
||||||
if (!rewardInfo) {
|
if (!rewardInfo) {
|
||||||
//TODO: if there is a case where you can have credits collected during a mission but no rewardInfo, add credits needs to be handled earlier
|
//TODO: if there is a case where you can have credits collected during a mission but no rewardInfo, add credits needs to be handled earlier
|
||||||
@ -578,22 +613,12 @@ export const addMissionRewards = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
//TODO: check double reward merging
|
//TODO: check double reward merging
|
||||||
const MissionRewards: IMissionReward[] = getRandomMissionDrops(rewardInfo, wagerTier);
|
const MissionRewards: IMissionReward[] = getRandomMissionDrops(inventory, rewardInfo, wagerTier, firstCompletion);
|
||||||
logger.debug("random mission drops:", MissionRewards);
|
logger.debug("random mission drops:", MissionRewards);
|
||||||
const inventoryChanges: IInventoryChanges = {};
|
const inventoryChanges: IInventoryChanges = {};
|
||||||
const AffiliationMods: IAffiliationMods[] = [];
|
const AffiliationMods: IAffiliationMods[] = [];
|
||||||
let SyndicateXPItemReward;
|
let SyndicateXPItemReward;
|
||||||
|
|
||||||
if (rewardInfo.sortieTag == "Final") {
|
|
||||||
inventory.LastSortieReward = [
|
|
||||||
{
|
|
||||||
SortieId: new Types.ObjectId(rewardInfo.sortieId!.split("_")[1]),
|
|
||||||
StoreItem: MissionRewards[0].StoreItem,
|
|
||||||
Manifest: "/Lotus/Types/Game/MissionDecks/SortieRewards"
|
|
||||||
}
|
|
||||||
];
|
|
||||||
}
|
|
||||||
|
|
||||||
let missionCompletionCredits = 0;
|
let missionCompletionCredits = 0;
|
||||||
//inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
|
//inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display
|
||||||
if (levelKeyName) {
|
if (levelKeyName) {
|
||||||
@ -695,6 +720,12 @@ export const addMissionRewards = async (
|
|||||||
|
|
||||||
if (strippedItems) {
|
if (strippedItems) {
|
||||||
for (const si of strippedItems) {
|
for (const si of strippedItems) {
|
||||||
|
if (si.DropTable == "/Lotus/Types/DropTables/ManInTheWall/MITWGruzzlingArcanesDropTable") {
|
||||||
|
logger.debug(
|
||||||
|
`rewriting ${si.DropTable} to /Lotus/Types/DropTables/EntratiLabDropTables/DoppelgangerDropTable`
|
||||||
|
);
|
||||||
|
si.DropTable = "/Lotus/Types/DropTables/EntratiLabDropTables/DoppelgangerDropTable";
|
||||||
|
}
|
||||||
const droptables = ExportEnemies.droptables[si.DropTable] ?? [];
|
const droptables = ExportEnemies.droptables[si.DropTable] ?? [];
|
||||||
if (si.DROP_MOD) {
|
if (si.DROP_MOD) {
|
||||||
const modDroptable = droptables.find(x => x.type == "mod");
|
const modDroptable = droptables.find(x => x.type == "mod");
|
||||||
@ -951,11 +982,74 @@ function getLevelCreditRewards(node: IRegion): number {
|
|||||||
//TODO: get dark sektor fixed credit rewards and railjack bonus
|
//TODO: get dark sektor fixed credit rewards and railjack bonus
|
||||||
}
|
}
|
||||||
|
|
||||||
function getRandomMissionDrops(RewardInfo: IRewardInfo, tierOverride: number | undefined): IMissionReward[] {
|
function getRandomMissionDrops(
|
||||||
|
inventory: TInventoryDatabaseDocument,
|
||||||
|
RewardInfo: IRewardInfo,
|
||||||
|
tierOverride: number | undefined,
|
||||||
|
firstCompletion: boolean
|
||||||
|
): IMissionReward[] {
|
||||||
const drops: IMissionReward[] = [];
|
const drops: IMissionReward[] = [];
|
||||||
if (RewardInfo.sortieTag == "Final") {
|
if (RewardInfo.sortieTag == "Final" && firstCompletion) {
|
||||||
|
const arr = RewardInfo.sortieId!.split("_");
|
||||||
|
let sortieId = arr[1];
|
||||||
|
if (sortieId == "Lite") {
|
||||||
|
sortieId = arr[2];
|
||||||
|
|
||||||
|
const boss = getLiteSortie(idToWeek(sortieId)).Boss;
|
||||||
|
let crystalType = {
|
||||||
|
SORTIE_BOSS_AMAR: "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalAmar",
|
||||||
|
SORTIE_BOSS_NIRA: "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalNira",
|
||||||
|
SORTIE_BOSS_BOREAL: "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalBoreal"
|
||||||
|
}[boss];
|
||||||
|
const attenTag = {
|
||||||
|
SORTIE_BOSS_AMAR: "NarmerSortieAmarCrystalRewards",
|
||||||
|
SORTIE_BOSS_NIRA: "NarmerSortieNiraCrystalRewards",
|
||||||
|
SORTIE_BOSS_BOREAL: "NarmerSortieBorealCrystalRewards"
|
||||||
|
}[boss];
|
||||||
|
const attenIndex = inventory.SortieRewardAttenuation?.findIndex(x => x.Tag == attenTag) ?? -1;
|
||||||
|
const mythicProbability =
|
||||||
|
0.2 + (inventory.SortieRewardAttenuation?.find(x => x.Tag == attenTag)?.Atten ?? 0);
|
||||||
|
if (Math.random() < mythicProbability) {
|
||||||
|
crystalType += "Mythic";
|
||||||
|
if (attenIndex != -1) {
|
||||||
|
inventory.SortieRewardAttenuation!.splice(attenIndex, 1);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
if (attenIndex == -1) {
|
||||||
|
inventory.SortieRewardAttenuation ??= [];
|
||||||
|
inventory.SortieRewardAttenuation.push({
|
||||||
|
Tag: attenTag,
|
||||||
|
Atten: 0.2
|
||||||
|
});
|
||||||
|
} else {
|
||||||
|
inventory.SortieRewardAttenuation![attenIndex].Atten += 0.2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drops.push({ StoreItem: crystalType, ItemCount: 1 });
|
||||||
|
|
||||||
|
const drop = getRandomRewardByChance(
|
||||||
|
ExportRewards["/Lotus/Types/Game/MissionDecks/ArchonSortieRewards"][0]
|
||||||
|
)!;
|
||||||
|
drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
|
||||||
|
inventory.LastLiteSortieReward = [
|
||||||
|
{
|
||||||
|
SortieId: new Types.ObjectId(sortieId),
|
||||||
|
StoreItem: drop.type,
|
||||||
|
Manifest: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
} else {
|
||||||
const drop = getRandomRewardByChance(ExportRewards["/Lotus/Types/Game/MissionDecks/SortieRewards"][0])!;
|
const drop = getRandomRewardByChance(ExportRewards["/Lotus/Types/Game/MissionDecks/SortieRewards"][0])!;
|
||||||
drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
|
drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount });
|
||||||
|
inventory.LastSortieReward = [
|
||||||
|
{
|
||||||
|
SortieId: new Types.ObjectId(sortieId),
|
||||||
|
StoreItem: drop.type,
|
||||||
|
Manifest: "/Lotus/Types/Game/MissionDecks/SortieRewards"
|
||||||
|
}
|
||||||
|
];
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (RewardInfo.periodicMissionTag?.startsWith("HardDaily")) {
|
if (RewardInfo.periodicMissionTag?.startsWith("HardDaily")) {
|
||||||
drops.push({
|
drops.push({
|
||||||
@ -965,10 +1059,16 @@ function getRandomMissionDrops(RewardInfo: IRewardInfo, tierOverride: number | u
|
|||||||
}
|
}
|
||||||
if (RewardInfo.node in ExportRegions) {
|
if (RewardInfo.node in ExportRegions) {
|
||||||
const region = ExportRegions[RewardInfo.node];
|
const region = ExportRegions[RewardInfo.node];
|
||||||
let rewardManifests: string[] =
|
let rewardManifests: string[];
|
||||||
RewardInfo.periodicMissionTag == "EliteAlert" || RewardInfo.periodicMissionTag == "EliteAlertB"
|
if (RewardInfo.periodicMissionTag == "EliteAlert" || RewardInfo.periodicMissionTag == "EliteAlertB") {
|
||||||
? ["/Lotus/Types/Game/MissionDecks/EliteAlertMissionRewards/EliteAlertMissionRewards"]
|
rewardManifests = ["/Lotus/Types/Game/MissionDecks/EliteAlertMissionRewards/EliteAlertMissionRewards"];
|
||||||
: region.rewardManifests;
|
} else if (RewardInfo.invasionId && region.missionIndex == 0) {
|
||||||
|
// Invasion assassination has Phorid has the boss who should drop Nyx parts
|
||||||
|
// TODO: Check that the invasion faction is indeed FC_INFESTATION once the Invasions in worldState are more dynamic
|
||||||
|
rewardManifests = ["/Lotus/Types/Game/MissionDecks/BossMissionRewards/NyxRewards"];
|
||||||
|
} else {
|
||||||
|
rewardManifests = region.rewardManifests;
|
||||||
|
}
|
||||||
|
|
||||||
let rotations: number[] = [];
|
let rotations: number[] = [];
|
||||||
if (RewardInfo.jobId) {
|
if (RewardInfo.jobId) {
|
||||||
|
@ -141,7 +141,8 @@ export const handlePurchase = async (
|
|||||||
inventory,
|
inventory,
|
||||||
purchaseRequest.PurchaseParams.Quantity,
|
purchaseRequest.PurchaseParams.Quantity,
|
||||||
undefined,
|
undefined,
|
||||||
undefined,
|
false,
|
||||||
|
purchaseRequest.PurchaseParams.UsePremium,
|
||||||
seed
|
seed
|
||||||
);
|
);
|
||||||
combineInventoryChanges(purchaseResponse.InventoryChanges, prePurchaseInventoryChanges);
|
combineInventoryChanges(purchaseResponse.InventoryChanges, prePurchaseInventoryChanges);
|
||||||
@ -331,6 +332,7 @@ export const handleStoreItemAcquisition = async (
|
|||||||
quantity: number = 1,
|
quantity: number = 1,
|
||||||
durability: TRarity = "COMMON",
|
durability: TRarity = "COMMON",
|
||||||
ignorePurchaseQuantity: boolean = false,
|
ignorePurchaseQuantity: boolean = false,
|
||||||
|
premiumPurchase: boolean = true,
|
||||||
seed?: bigint
|
seed?: bigint
|
||||||
): Promise<IPurchaseResponse> => {
|
): Promise<IPurchaseResponse> => {
|
||||||
let purchaseResponse = {
|
let purchaseResponse = {
|
||||||
@ -352,11 +354,20 @@ export const handleStoreItemAcquisition = async (
|
|||||||
}
|
}
|
||||||
switch (storeCategory) {
|
switch (storeCategory) {
|
||||||
default: {
|
default: {
|
||||||
purchaseResponse = { InventoryChanges: await addItem(inventory, internalName, quantity, true, seed) };
|
purchaseResponse = {
|
||||||
|
InventoryChanges: await addItem(inventory, internalName, quantity, premiumPurchase, seed)
|
||||||
|
};
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "Types":
|
case "Types":
|
||||||
purchaseResponse = await handleTypesPurchase(internalName, inventory, quantity, ignorePurchaseQuantity);
|
purchaseResponse = await handleTypesPurchase(
|
||||||
|
internalName,
|
||||||
|
inventory,
|
||||||
|
quantity,
|
||||||
|
ignorePurchaseQuantity,
|
||||||
|
premiumPurchase,
|
||||||
|
seed
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
case "Boosters":
|
case "Boosters":
|
||||||
purchaseResponse = handleBoostersPurchase(storeItemName, inventory, durability);
|
purchaseResponse = handleBoostersPurchase(storeItemName, inventory, durability);
|
||||||
@ -478,13 +489,15 @@ const handleTypesPurchase = async (
|
|||||||
typesName: string,
|
typesName: string,
|
||||||
inventory: TInventoryDatabaseDocument,
|
inventory: TInventoryDatabaseDocument,
|
||||||
quantity: number,
|
quantity: number,
|
||||||
ignorePurchaseQuantity: boolean
|
ignorePurchaseQuantity: boolean,
|
||||||
|
premiumPurchase: boolean = true,
|
||||||
|
seed?: bigint
|
||||||
): Promise<IPurchaseResponse> => {
|
): Promise<IPurchaseResponse> => {
|
||||||
const typeCategory = getStoreItemTypesCategory(typesName);
|
const typeCategory = getStoreItemTypesCategory(typesName);
|
||||||
logger.debug(`type category ${typeCategory}`);
|
logger.debug(`type category ${typeCategory}`);
|
||||||
switch (typeCategory) {
|
switch (typeCategory) {
|
||||||
default:
|
default:
|
||||||
return { InventoryChanges: await addItem(inventory, typesName, quantity) };
|
return { InventoryChanges: await addItem(inventory, typesName, quantity, premiumPurchase, seed) };
|
||||||
case "BoosterPacks":
|
case "BoosterPacks":
|
||||||
return handleBoosterPackPurchase(typesName, inventory, quantity);
|
return handleBoosterPackPurchase(typesName, inventory, quantity);
|
||||||
case "SlotItems":
|
case "SlotItems":
|
||||||
|
@ -216,6 +216,27 @@ const handleQuestCompletion = async (
|
|||||||
setupKahlSyndicate(inventory);
|
setupKahlSyndicate(inventory);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Whispers in the Walls is unlocked once The New + Heart of Deimos are completed.
|
||||||
|
if (
|
||||||
|
(questKey == "/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain" &&
|
||||||
|
inventory.QuestKeys.find(
|
||||||
|
x => x.ItemType == "/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain"
|
||||||
|
)?.Completed) ||
|
||||||
|
(questKey == "/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain" &&
|
||||||
|
inventory.QuestKeys.find(x => x.ItemType == "/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain")?.Completed)
|
||||||
|
) {
|
||||||
|
await createMessage(inventory.accountOwnerId, [
|
||||||
|
{
|
||||||
|
sndr: "/Lotus/Language/Bosses/Loid",
|
||||||
|
msg: "/Lotus/Language/EntratiLab/EntratiQuest/WiTWQuestRecievedInboxBody",
|
||||||
|
att: ["/Lotus/Types/Keys/EntratiLab/EntratiQuestKeyChain"],
|
||||||
|
sub: "/Lotus/Language/EntratiLab/EntratiQuest/WiTWQuestRecievedInboxTitle",
|
||||||
|
icon: "/Lotus/Interface/Icons/Npcs/Entrati/Loid.png",
|
||||||
|
highPriority: true
|
||||||
|
}
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
|
||||||
const questCompletionItems = getQuestCompletionItems(questKey);
|
const questCompletionItems = getQuestCompletionItems(questKey);
|
||||||
logger.debug(`quest completion items`, questCompletionItems);
|
logger.debug(`quest completion items`, questCompletionItems);
|
||||||
if (questCompletionItems) {
|
if (questCompletionItems) {
|
||||||
|
@ -13,6 +13,8 @@ import { Types } from "mongoose";
|
|||||||
import { isEmptyObject } from "@/src/helpers/general";
|
import { isEmptyObject } from "@/src/helpers/general";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { equipmentKeys, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
import { equipmentKeys, TEquipmentKey } from "@/src/types/inventoryTypes/inventoryTypes";
|
||||||
|
import { IItemConfig } from "../types/inventoryTypes/commonInventoryTypes";
|
||||||
|
import { importCrewMemberId } from "./importService";
|
||||||
|
|
||||||
//TODO: setup default items on account creation or like originally in giveStartingItems.php
|
//TODO: setup default items on account creation or like originally in giveStartingItems.php
|
||||||
|
|
||||||
@ -174,8 +176,8 @@ export const handleInventoryItemConfigChange = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (const [configId, config] of Object.entries(itemConfigEntries)) {
|
for (const [configId, config] of Object.entries(itemConfigEntries)) {
|
||||||
if (typeof config !== "boolean") {
|
if (/^[0-9]+$/.test(configId)) {
|
||||||
inventoryItem.Configs[parseInt(configId)] = config;
|
inventoryItem.Configs[parseInt(configId)] = config as IItemConfig;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if ("Favorite" in itemConfigEntries) {
|
if ("Favorite" in itemConfigEntries) {
|
||||||
@ -184,6 +186,26 @@ export const handleInventoryItemConfigChange = async (
|
|||||||
if ("IsNew" in itemConfigEntries) {
|
if ("IsNew" in itemConfigEntries) {
|
||||||
inventoryItem.IsNew = itemConfigEntries.IsNew;
|
inventoryItem.IsNew = itemConfigEntries.IsNew;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if ("ItemName" in itemConfigEntries) {
|
||||||
|
inventoryItem.ItemName = itemConfigEntries.ItemName;
|
||||||
|
}
|
||||||
|
if ("RailjackImage" in itemConfigEntries) {
|
||||||
|
inventoryItem.RailjackImage = itemConfigEntries.RailjackImage;
|
||||||
|
}
|
||||||
|
if ("Customization" in itemConfigEntries) {
|
||||||
|
inventoryItem.Customization = itemConfigEntries.Customization;
|
||||||
|
}
|
||||||
|
if ("Weapon" in itemConfigEntries) {
|
||||||
|
inventoryItem.Weapon = itemConfigEntries.Weapon;
|
||||||
|
}
|
||||||
|
if (itemConfigEntries.CrewMembers) {
|
||||||
|
inventoryItem.CrewMembers = {
|
||||||
|
SLOT_A: importCrewMemberId(itemConfigEntries.CrewMembers.SLOT_A ?? {}),
|
||||||
|
SLOT_B: importCrewMemberId(itemConfigEntries.CrewMembers.SLOT_B ?? {}),
|
||||||
|
SLOT_C: importCrewMemberId(itemConfigEntries.CrewMembers.SLOT_C ?? {})
|
||||||
|
};
|
||||||
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
} else {
|
} else {
|
||||||
|
@ -1,6 +1,4 @@
|
|||||||
import fs from "fs";
|
import { unixTimesInMs } from "@/src/constants/timeConstants";
|
||||||
import path from "path";
|
|
||||||
import { repoDir } from "@/src/helpers/pathHelper";
|
|
||||||
import { CRng, mixSeeds } from "@/src/services/rngService";
|
import { CRng, mixSeeds } from "@/src/services/rngService";
|
||||||
import { IMongoDate } from "@/src/types/commonTypes";
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
import {
|
import {
|
||||||
@ -9,49 +7,73 @@ import {
|
|||||||
IVendorInfo,
|
IVendorInfo,
|
||||||
IVendorManifestPreprocessed
|
IVendorManifestPreprocessed
|
||||||
} from "@/src/types/vendorTypes";
|
} from "@/src/types/vendorTypes";
|
||||||
import { JSONParse } from "json-with-bigint";
|
|
||||||
import { ExportVendors } from "warframe-public-export-plus";
|
import { ExportVendors } from "warframe-public-export-plus";
|
||||||
import { unixTimesInMs } from "../constants/timeConstants";
|
|
||||||
|
|
||||||
const getVendorManifestJson = (name: string): IRawVendorManifest => {
|
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
||||||
return JSONParse(fs.readFileSync(path.join(repoDir, `static/fixed_responses/getVendorInfo/${name}.json`), "utf-8"));
|
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";
|
||||||
|
import DeimosHivemindCommisionsManifestTokenVendor from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestTokenVendor.json";
|
||||||
|
import DeimosHivemindCommisionsManifestWeaponsmith from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestWeaponsmith.json";
|
||||||
|
import DeimosHivemindTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosHivemindTokenVendorManifest.json";
|
||||||
|
import DeimosPetVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosPetVendorManifest.json";
|
||||||
|
import DeimosProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosProspectorVendorManifest.json";
|
||||||
|
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
|
||||||
|
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
|
||||||
|
import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
|
||||||
|
import GuildAdvertisementVendorManifest from "@/static/fixed_responses/getVendorInfo/GuildAdvertisementVendorManifest.json";
|
||||||
|
import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsIronwakeDondaVendorManifest.json";
|
||||||
|
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
|
||||||
|
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
|
||||||
|
import 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 SolarisDebtTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorManifest.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 TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
|
||||||
|
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
||||||
|
|
||||||
const rawVendorManifests: IRawVendorManifest[] = [
|
const rawVendorManifests: IRawVendorManifest[] = [
|
||||||
getVendorManifestJson("ArchimedeanVendorManifest"),
|
ArchimedeanVendorManifest,
|
||||||
getVendorManifestJson("DeimosEntratiFragmentVendorProductsManifest"),
|
DeimosEntratiFragmentVendorProductsManifest,
|
||||||
getVendorManifestJson("DeimosFishmongerVendorManifest"),
|
DeimosFishmongerVendorManifest,
|
||||||
getVendorManifestJson("DeimosHivemindCommisionsManifestFishmonger"),
|
DeimosHivemindCommisionsManifestFishmonger,
|
||||||
getVendorManifestJson("DeimosHivemindCommisionsManifestPetVendor"),
|
DeimosHivemindCommisionsManifestPetVendor,
|
||||||
getVendorManifestJson("DeimosHivemindCommisionsManifestProspector"),
|
DeimosHivemindCommisionsManifestProspector,
|
||||||
getVendorManifestJson("DeimosHivemindCommisionsManifestTokenVendor"),
|
DeimosHivemindCommisionsManifestTokenVendor,
|
||||||
getVendorManifestJson("DeimosHivemindCommisionsManifestWeaponsmith"),
|
DeimosHivemindCommisionsManifestWeaponsmith,
|
||||||
getVendorManifestJson("DeimosHivemindTokenVendorManifest"),
|
DeimosHivemindTokenVendorManifest,
|
||||||
getVendorManifestJson("DeimosPetVendorManifest"),
|
DeimosPetVendorManifest,
|
||||||
getVendorManifestJson("DeimosProspectorVendorManifest"),
|
DeimosProspectorVendorManifest,
|
||||||
getVendorManifestJson("DuviriAcrithisVendorManifest"),
|
DuviriAcrithisVendorManifest,
|
||||||
getVendorManifestJson("EntratiLabsEntratiLabsCommisionsManifest"),
|
EntratiLabsEntratiLabsCommisionsManifest,
|
||||||
getVendorManifestJson("EntratiLabsEntratiLabVendorManifest"),
|
EntratiLabsEntratiLabVendorManifest,
|
||||||
getVendorManifestJson("GuildAdvertisementVendorManifest"), // uses preprocessing
|
GuildAdvertisementVendorManifest, // uses preprocessing
|
||||||
getVendorManifestJson("HubsIronwakeDondaVendorManifest"), // uses preprocessing
|
HubsIronwakeDondaVendorManifest, // uses preprocessing
|
||||||
getVendorManifestJson("HubsPerrinSequenceWeaponVendorManifest"),
|
HubsRailjackCrewMemberVendorManifest,
|
||||||
getVendorManifestJson("HubsRailjackCrewMemberVendorManifest"),
|
MaskSalesmanManifest,
|
||||||
getVendorManifestJson("MaskSalesmanManifest"),
|
Nova1999ConquestShopManifest,
|
||||||
getVendorManifestJson("Nova1999ConquestShopManifest"),
|
OstronFishmongerVendorManifest,
|
||||||
getVendorManifestJson("OstronFishmongerVendorManifest"),
|
OstronPetVendorManifest,
|
||||||
getVendorManifestJson("OstronPetVendorManifest"),
|
OstronProspectorVendorManifest,
|
||||||
getVendorManifestJson("OstronProspectorVendorManifest"),
|
RadioLegionIntermission12VendorManifest,
|
||||||
getVendorManifestJson("RadioLegionIntermission12VendorManifest"),
|
SolarisDebtTokenVendorManifest,
|
||||||
getVendorManifestJson("SolarisDebtTokenVendorManifest"),
|
SolarisDebtTokenVendorRepossessionsManifest,
|
||||||
getVendorManifestJson("SolarisDebtTokenVendorRepossessionsManifest"),
|
SolarisFishmongerVendorManifest,
|
||||||
getVendorManifestJson("SolarisFishmongerVendorManifest"),
|
SolarisProspectorVendorManifest,
|
||||||
getVendorManifestJson("SolarisProspectorVendorManifest"),
|
TeshinHardModeVendorManifest, // uses preprocessing
|
||||||
getVendorManifestJson("TeshinHardModeVendorManifest"), // uses preprocessing
|
ZarimanCommisionsManifestArchimedean
|
||||||
getVendorManifestJson("ZarimanCommisionsManifestArchimedean")
|
|
||||||
];
|
];
|
||||||
|
|
||||||
interface IGeneratableVendorInfo extends Omit<IVendorInfo, "ItemManifest" | "Expiry"> {
|
interface IGeneratableVendorInfo extends Omit<IVendorInfo, "ItemManifest" | "Expiry"> {
|
||||||
cycleDuration?: number;
|
cycleStart: number;
|
||||||
|
cycleDuration: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
const generatableVendors: IGeneratableVendorInfo[] = [
|
const generatableVendors: IGeneratableVendorInfo[] = [
|
||||||
@ -62,6 +84,16 @@ const generatableVendors: IGeneratableVendorInfo[] = [
|
|||||||
RandomSeedType: "VRST_WEAPON",
|
RandomSeedType: "VRST_WEAPON",
|
||||||
RequiredGoalTag: "",
|
RequiredGoalTag: "",
|
||||||
WeaponUpgradeValueAttenuationExponent: 2.25,
|
WeaponUpgradeValueAttenuationExponent: 2.25,
|
||||||
|
cycleStart: 1740960000_000,
|
||||||
|
cycleDuration: 4 * unixTimesInMs.day
|
||||||
|
},
|
||||||
|
{
|
||||||
|
_id: { $oid: "60ad3b6ec96976e97d227e19" },
|
||||||
|
TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/PerrinSequenceWeaponVendorManifest",
|
||||||
|
PropertyTextHash: "34F8CF1DFF745F0D67433A5EF0A03E70",
|
||||||
|
RandomSeedType: "VRST_WEAPON",
|
||||||
|
WeaponUpgradeValueAttenuationExponent: 2.25,
|
||||||
|
cycleStart: 1744934400_000,
|
||||||
cycleDuration: 4 * unixTimesInMs.day
|
cycleDuration: 4 * unixTimesInMs.day
|
||||||
}
|
}
|
||||||
// {
|
// {
|
||||||
@ -124,7 +156,7 @@ const preprocessVendorManifest = (originalManifest: IRawVendorManifest): IVendor
|
|||||||
const refreshExpiry = (expiry: IMongoDate): number => {
|
const refreshExpiry = (expiry: IMongoDate): number => {
|
||||||
const period = parseInt(expiry.$date.$numberLong);
|
const period = parseInt(expiry.$date.$numberLong);
|
||||||
if (Date.now() >= period) {
|
if (Date.now() >= period) {
|
||||||
const epoch = 1734307200 * 1000; // Monday (for weekly schedules)
|
const epoch = 1734307200_000; // Monday (for weekly schedules)
|
||||||
const iteration = Math.trunc((Date.now() - epoch) / period);
|
const iteration = Math.trunc((Date.now() - epoch) / period);
|
||||||
const start = epoch + iteration * period;
|
const start = epoch + iteration * period;
|
||||||
const end = start + period;
|
const end = start + period;
|
||||||
@ -135,11 +167,11 @@ const refreshExpiry = (expiry: IMongoDate): number => {
|
|||||||
};
|
};
|
||||||
|
|
||||||
const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifestPreprocessed => {
|
const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifestPreprocessed => {
|
||||||
const EPOCH = 1740960000 * 1000; // Monday; aligns with coda weapons 8 day cycle.
|
const EPOCH = vendorInfo.cycleStart;
|
||||||
const manifest = ExportVendors[vendorInfo.TypeName];
|
const manifest = ExportVendors[vendorInfo.TypeName];
|
||||||
let binThisCycle;
|
let binThisCycle;
|
||||||
if (manifest.isOneBinPerCycle) {
|
if (manifest.isOneBinPerCycle) {
|
||||||
const cycleDuration = vendorInfo.cycleDuration!; // manifest.items[0].durationHours! * 3600_000;
|
const cycleDuration = vendorInfo.cycleDuration; // manifest.items[0].durationHours! * 3600_000;
|
||||||
const cycleIndex = Math.trunc((Date.now() - EPOCH) / cycleDuration);
|
const cycleIndex = Math.trunc((Date.now() - EPOCH) / cycleDuration);
|
||||||
binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
|
binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
|
||||||
}
|
}
|
||||||
@ -150,7 +182,7 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
if (manifest.isOneBinPerCycle && rawItem.bin != binThisCycle) {
|
if (manifest.isOneBinPerCycle && rawItem.bin != binThisCycle) {
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const cycleDuration = vendorInfo.cycleDuration!; // rawItem.durationHours! * 3600_000;
|
const cycleDuration = vendorInfo.cycleDuration; // rawItem.durationHours! * 3600_000;
|
||||||
const cycleIndex = Math.trunc((Date.now() - EPOCH) / cycleDuration);
|
const cycleIndex = Math.trunc((Date.now() - EPOCH) / cycleDuration);
|
||||||
const cycleStart = EPOCH + cycleIndex * cycleDuration;
|
const cycleStart = EPOCH + cycleIndex * cycleDuration;
|
||||||
const cycleEnd = cycleStart + cycleDuration;
|
const cycleEnd = cycleStart + cycleDuration;
|
||||||
@ -181,10 +213,11 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
items.push(item);
|
items.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
delete vendorInfo.cycleDuration;
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
|
const { cycleStart, cycleDuration, ...clientVendorInfo } = vendorInfo;
|
||||||
return {
|
return {
|
||||||
VendorInfo: {
|
VendorInfo: {
|
||||||
...vendorInfo,
|
...clientVendorInfo,
|
||||||
ItemManifest: items,
|
ItemManifest: items,
|
||||||
Expiry: { $date: { $numberLong: soonestOfferExpiry.toString() } }
|
Expiry: { $date: { $numberLong: soonestOfferExpiry.toString() } }
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,5 @@
|
|||||||
import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
|
import { Stats, TStatsDatabaseDocument } from "@/src/models/statsModel";
|
||||||
import {
|
import {
|
||||||
IEnemy,
|
|
||||||
IStatsAdd,
|
IStatsAdd,
|
||||||
IStatsMax,
|
IStatsMax,
|
||||||
IStatsSet,
|
IStatsSet,
|
||||||
@ -137,16 +136,21 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate)
|
|||||||
case "HEADSHOT":
|
case "HEADSHOT":
|
||||||
case "KILL_ASSIST": {
|
case "KILL_ASSIST": {
|
||||||
playerStats.Enemies ??= [];
|
playerStats.Enemies ??= [];
|
||||||
const enemyStatKey = {
|
const enemyStatKey = (
|
||||||
|
{
|
||||||
KILL_ENEMY: "kills",
|
KILL_ENEMY: "kills",
|
||||||
EXECUTE_ENEMY: "executions",
|
EXECUTE_ENEMY: "executions",
|
||||||
HEADSHOT: "headshots",
|
HEADSHOT: "headshots",
|
||||||
KILL_ASSIST: "assists"
|
KILL_ASSIST: "assists"
|
||||||
}[category] as "kills" | "executions" | "headshots" | "assists";
|
} as const
|
||||||
|
)[category];
|
||||||
|
|
||||||
for (const [type, count] of Object.entries(data as IUploadEntry)) {
|
for (const [type, count] of Object.entries(data as IUploadEntry)) {
|
||||||
const enemy = playerStats.Enemies.find(element => element.type === type);
|
let enemy = playerStats.Enemies.find(element => element.type === type);
|
||||||
if (enemy) {
|
if (!enemy) {
|
||||||
|
enemy = { type: type };
|
||||||
|
playerStats.Enemies.push(enemy);
|
||||||
|
}
|
||||||
if (category === "KILL_ENEMY") {
|
if (category === "KILL_ENEMY") {
|
||||||
enemy.kills ??= 0;
|
enemy.kills ??= 0;
|
||||||
const captureCount = (actionData as IStatsAdd)["CAPTURE_ENEMY"]?.[type];
|
const captureCount = (actionData as IStatsAdd)["CAPTURE_ENEMY"]?.[type];
|
||||||
@ -161,11 +165,6 @@ export const updateStats = async (accountOwnerId: string, payload: IStatsUpdate)
|
|||||||
enemy[enemyStatKey] ??= 0;
|
enemy[enemyStatKey] ??= 0;
|
||||||
enemy[enemyStatKey] += count;
|
enemy[enemyStatKey] += count;
|
||||||
}
|
}
|
||||||
} else {
|
|
||||||
const newEnemy: IEnemy = { type: type };
|
|
||||||
newEnemy[enemyStatKey] = count;
|
|
||||||
playerStats.Enemies.push(newEnemy);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
@ -4,7 +4,14 @@ import { unixTimesInMs } from "@/src/constants/timeConstants";
|
|||||||
import { config } from "@/src/services/configService";
|
import { config } from "@/src/services/configService";
|
||||||
import { CRng } from "@/src/services/rngService";
|
import { CRng } from "@/src/services/rngService";
|
||||||
import { eMissionType, ExportNightwave, ExportRegions } from "warframe-public-export-plus";
|
import { eMissionType, ExportNightwave, ExportRegions } from "warframe-public-export-plus";
|
||||||
import { ICalendarDay, ICalendarSeason, ISeasonChallenge, ISortie, IWorldState } from "../types/worldStateTypes";
|
import {
|
||||||
|
ICalendarDay,
|
||||||
|
ICalendarSeason,
|
||||||
|
ILiteSortie,
|
||||||
|
ISeasonChallenge,
|
||||||
|
ISortie,
|
||||||
|
IWorldState
|
||||||
|
} from "../types/worldStateTypes";
|
||||||
|
|
||||||
const sortieBosses = [
|
const sortieBosses = [
|
||||||
"SORTIE_BOSS_HYENA",
|
"SORTIE_BOSS_HYENA",
|
||||||
@ -348,6 +355,34 @@ const getSeasonWeeklyHardChallenge = (week: number, id: number): ISeasonChalleng
|
|||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const pushWeeklyActs = (worldState: IWorldState, week: number): void => {
|
||||||
|
const weekStart = EPOCH + week * 604800000;
|
||||||
|
const weekEnd = weekStart + 604800000;
|
||||||
|
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyChallenge(week, 0));
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyChallenge(week, 1));
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyHardChallenge(week, 2));
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyHardChallenge(week, 3));
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push({
|
||||||
|
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 0).toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentCompleteMissions" + (week - 12)
|
||||||
|
});
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push({
|
||||||
|
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 1).toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEximus" + (week - 12)
|
||||||
|
});
|
||||||
|
worldState.SeasonInfo.ActiveChallenges.push({
|
||||||
|
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 2).toString().padStart(8, "0") },
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies" + (week - 12)
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
const birthdays: number[] = [
|
const birthdays: number[] = [
|
||||||
1, // Kaya
|
1, // Kaya
|
||||||
45, // Lettie
|
45, // Lettie
|
||||||
@ -604,29 +639,10 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
if (isBeforeNextExpectedWorldStateRefresh(EPOCH + (day + 1) * 86400000)) {
|
if (isBeforeNextExpectedWorldStateRefresh(EPOCH + (day + 1) * 86400000)) {
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day + 1));
|
worldState.SeasonInfo.ActiveChallenges.push(getSeasonDailyChallenge(day + 1));
|
||||||
}
|
}
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyChallenge(week, 0));
|
pushWeeklyActs(worldState, week);
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyChallenge(week, 1));
|
if (isBeforeNextExpectedWorldStateRefresh(weekEnd)) {
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyHardChallenge(week, 2));
|
pushWeeklyActs(worldState, week + 1);
|
||||||
worldState.SeasonInfo.ActiveChallenges.push(getSeasonWeeklyHardChallenge(week, 3));
|
}
|
||||||
worldState.SeasonInfo.ActiveChallenges.push({
|
|
||||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 0).toString().padStart(8, "0") },
|
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
|
||||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentCompleteMissions" + (week - 12)
|
|
||||||
});
|
|
||||||
worldState.SeasonInfo.ActiveChallenges.push({
|
|
||||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 1).toString().padStart(8, "0") },
|
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
|
||||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEximus" + (week - 12)
|
|
||||||
});
|
|
||||||
worldState.SeasonInfo.ActiveChallenges.push({
|
|
||||||
_id: { $oid: "67e1b96e9d00cb47" + (week * 7 + 2).toString().padStart(8, "0") },
|
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
|
||||||
Challenge: "/Lotus/Types/Challenges/Seasons/Weekly/SeasonWeeklyPermanentKillEnemies" + (week - 12)
|
|
||||||
});
|
|
||||||
// TODO: Provide upcoming weekly acts if rollover is imminent
|
|
||||||
|
|
||||||
// Elite Sanctuary Onslaught cycling every week
|
// Elite Sanctuary Onslaught cycling every week
|
||||||
worldState.NodeOverrides.find(x => x.Node == "SolNode802")!.Seed = week; // unfaithful
|
worldState.NodeOverrides.find(x => x.Node == "SolNode802")!.Seed = week; // unfaithful
|
||||||
@ -941,65 +957,9 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
pushSortieIfRelevant(worldState.Sorties, day);
|
pushSortieIfRelevant(worldState.Sorties, day);
|
||||||
|
|
||||||
// Archon Hunt cycling every week
|
// Archon Hunt cycling every week
|
||||||
// TODO: Handle imminent rollover
|
worldState.LiteSorties.push(getLiteSortie(week));
|
||||||
{
|
if (isBeforeNextExpectedWorldStateRefresh(weekEnd)) {
|
||||||
const boss = ["SORTIE_BOSS_AMAR", "SORTIE_BOSS_NIRA", "SORTIE_BOSS_BOREAL"][week % 3];
|
worldState.LiteSorties.push(getLiteSortie(week + 1));
|
||||||
const showdownNode = ["SolNode99", "SolNode53", "SolNode24"][week % 3];
|
|
||||||
const systemIndex = [3, 4, 2][week % 3]; // Mars, Jupiter, Earth
|
|
||||||
|
|
||||||
const nodes: string[] = [];
|
|
||||||
for (const [key, value] of Object.entries(ExportRegions)) {
|
|
||||||
if (
|
|
||||||
value.systemIndex === systemIndex &&
|
|
||||||
value.factionIndex !== undefined &&
|
|
||||||
value.factionIndex < 2 &&
|
|
||||||
value.name.indexOf("Archwing") == -1 &&
|
|
||||||
value.missionIndex != 0 // Exclude MT_ASSASSINATION
|
|
||||||
) {
|
|
||||||
nodes.push(key);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const rng = new CRng(week);
|
|
||||||
const firstNodeIndex = rng.randomInt(0, nodes.length - 1);
|
|
||||||
const firstNode = nodes[firstNodeIndex];
|
|
||||||
nodes.splice(firstNodeIndex, 1);
|
|
||||||
worldState.LiteSorties.push({
|
|
||||||
_id: {
|
|
||||||
$oid: Math.trunc(weekStart / 1000).toString(16) + "5e23a244740a190c"
|
|
||||||
},
|
|
||||||
Activation: { $date: { $numberLong: weekStart.toString() } },
|
|
||||||
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
|
||||||
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards",
|
|
||||||
Seed: week,
|
|
||||||
Boss: boss,
|
|
||||||
Missions: [
|
|
||||||
{
|
|
||||||
missionType: rng.randomElement([
|
|
||||||
"MT_INTEL",
|
|
||||||
"MT_MOBILE_DEFENSE",
|
|
||||||
"MT_EXTERMINATION",
|
|
||||||
"MT_SABOTAGE",
|
|
||||||
"MT_RESCUE"
|
|
||||||
]),
|
|
||||||
node: firstNode
|
|
||||||
},
|
|
||||||
{
|
|
||||||
missionType: rng.randomElement([
|
|
||||||
"MT_DEFENSE",
|
|
||||||
"MT_TERRITORY",
|
|
||||||
"MT_ARTIFACT",
|
|
||||||
"MT_EXCAVATE",
|
|
||||||
"MT_SURVIVAL"
|
|
||||||
]),
|
|
||||||
node: rng.randomElement(nodes)
|
|
||||||
},
|
|
||||||
{
|
|
||||||
missionType: "MT_ASSASSINATION",
|
|
||||||
node: showdownNode
|
|
||||||
}
|
|
||||||
]
|
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Circuit choices cycling every week
|
// Circuit choices cycling every week
|
||||||
@ -1071,3 +1031,70 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
|
|||||||
|
|
||||||
return worldState;
|
return worldState;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
export const idToWeek = (id: string): number => {
|
||||||
|
return (parseInt(id.substring(0, 8), 16) * 1000 - EPOCH) / 604800000;
|
||||||
|
};
|
||||||
|
|
||||||
|
export const getLiteSortie = (week: number): ILiteSortie => {
|
||||||
|
const boss = (["SORTIE_BOSS_AMAR", "SORTIE_BOSS_NIRA", "SORTIE_BOSS_BOREAL"] as const)[week % 3];
|
||||||
|
const showdownNode = ["SolNode99", "SolNode53", "SolNode24"][week % 3];
|
||||||
|
const systemIndex = [3, 4, 2][week % 3]; // Mars, Jupiter, Earth
|
||||||
|
|
||||||
|
const nodes: string[] = [];
|
||||||
|
for (const [key, value] of Object.entries(ExportRegions)) {
|
||||||
|
if (
|
||||||
|
value.systemIndex === systemIndex &&
|
||||||
|
value.factionIndex !== undefined &&
|
||||||
|
value.factionIndex < 2 &&
|
||||||
|
value.name.indexOf("Archwing") == -1 &&
|
||||||
|
value.missionIndex != 0 // Exclude MT_ASSASSINATION
|
||||||
|
) {
|
||||||
|
nodes.push(key);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
const rng = new CRng(week);
|
||||||
|
const firstNodeIndex = rng.randomInt(0, nodes.length - 1);
|
||||||
|
const firstNode = nodes[firstNodeIndex];
|
||||||
|
nodes.splice(firstNodeIndex, 1);
|
||||||
|
|
||||||
|
const weekStart = EPOCH + week * 604800000;
|
||||||
|
const weekEnd = weekStart + 604800000;
|
||||||
|
return {
|
||||||
|
_id: {
|
||||||
|
$oid: Math.trunc(weekStart / 1000).toString(16) + "5e23a244740a190c"
|
||||||
|
},
|
||||||
|
Activation: { $date: { $numberLong: weekStart.toString() } },
|
||||||
|
Expiry: { $date: { $numberLong: weekEnd.toString() } },
|
||||||
|
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards",
|
||||||
|
Seed: week,
|
||||||
|
Boss: boss,
|
||||||
|
Missions: [
|
||||||
|
{
|
||||||
|
missionType: rng.randomElement([
|
||||||
|
"MT_INTEL",
|
||||||
|
"MT_MOBILE_DEFENSE",
|
||||||
|
"MT_EXTERMINATION",
|
||||||
|
"MT_SABOTAGE",
|
||||||
|
"MT_RESCUE"
|
||||||
|
]),
|
||||||
|
node: firstNode
|
||||||
|
},
|
||||||
|
{
|
||||||
|
missionType: rng.randomElement([
|
||||||
|
"MT_DEFENSE",
|
||||||
|
"MT_TERRITORY",
|
||||||
|
"MT_ARTIFACT",
|
||||||
|
"MT_EXCAVATE",
|
||||||
|
"MT_SURVIVAL"
|
||||||
|
]),
|
||||||
|
node: rng.randomElement(nodes)
|
||||||
|
},
|
||||||
|
{
|
||||||
|
missionType: "MT_ASSASSINATION",
|
||||||
|
node: showdownNode
|
||||||
|
}
|
||||||
|
]
|
||||||
|
};
|
||||||
|
};
|
||||||
|
@ -103,12 +103,12 @@ export interface IGuildMemberDatabase {
|
|||||||
ShipDecorationsContributed?: ITypeCount[];
|
ShipDecorationsContributed?: ITypeCount[];
|
||||||
}
|
}
|
||||||
|
|
||||||
interface IFriendInfo {
|
export interface IFriendInfo {
|
||||||
_id: IOid;
|
_id: IOid;
|
||||||
DisplayName?: string;
|
DisplayName?: string;
|
||||||
PlatformNames?: string[];
|
PlatformNames?: string[];
|
||||||
PlatformAccountId?: string;
|
PlatformAccountId?: string;
|
||||||
Status: number;
|
Status?: number;
|
||||||
ActiveAvatarImageType?: string;
|
ActiveAvatarImageType?: string;
|
||||||
LastLogin?: IMongoDate;
|
LastLogin?: IMongoDate;
|
||||||
PlayerLevel?: number;
|
PlayerLevel?: number;
|
||||||
|
@ -49,6 +49,8 @@ export interface IInventoryDatabase
|
|||||||
| "PersonalTechProjects"
|
| "PersonalTechProjects"
|
||||||
| "LastSortieReward"
|
| "LastSortieReward"
|
||||||
| "LastLiteSortieReward"
|
| "LastLiteSortieReward"
|
||||||
|
| "CrewMembers"
|
||||||
|
| "QualifyingInvasions"
|
||||||
| TEquipmentKey
|
| TEquipmentKey
|
||||||
>,
|
>,
|
||||||
InventoryDatabaseEquipment {
|
InventoryDatabaseEquipment {
|
||||||
@ -83,6 +85,8 @@ export interface IInventoryDatabase
|
|||||||
PersonalTechProjects: IPersonalTechProjectDatabase[];
|
PersonalTechProjects: IPersonalTechProjectDatabase[];
|
||||||
LastSortieReward?: ILastSortieRewardDatabase[];
|
LastSortieReward?: ILastSortieRewardDatabase[];
|
||||||
LastLiteSortieReward?: ILastSortieRewardDatabase[];
|
LastLiteSortieReward?: ILastSortieRewardDatabase[];
|
||||||
|
CrewMembers: ICrewMemberDatabase[];
|
||||||
|
QualifyingInvasions: IInvasionProgressDatabase[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IQuestKeyDatabase {
|
export interface IQuestKeyDatabase {
|
||||||
@ -246,9 +250,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
Guide?: number;
|
Guide?: number;
|
||||||
Moderator?: boolean;
|
Moderator?: boolean;
|
||||||
Partner?: boolean;
|
Partner?: boolean;
|
||||||
Accolades?: {
|
Accolades?: IAccolades;
|
||||||
Heirloom?: boolean;
|
|
||||||
};
|
|
||||||
Counselor?: boolean;
|
Counselor?: boolean;
|
||||||
Upgrades: IUpgradeClient[];
|
Upgrades: IUpgradeClient[];
|
||||||
EquippedGear: string[];
|
EquippedGear: string[];
|
||||||
@ -270,7 +272,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
SentientSpawnChanceBoosters: ISentientSpawnChanceBoosters;
|
SentientSpawnChanceBoosters: ISentientSpawnChanceBoosters;
|
||||||
SupportedSyndicate?: string;
|
SupportedSyndicate?: string;
|
||||||
Affiliations: IAffiliation[];
|
Affiliations: IAffiliation[];
|
||||||
QualifyingInvasions: any[];
|
QualifyingInvasions: IInvasionProgressClient[];
|
||||||
FactionScores: number[];
|
FactionScores: number[];
|
||||||
ArchwingEnabled?: boolean;
|
ArchwingEnabled?: boolean;
|
||||||
PendingSpectreLoadouts?: ISpectreLoadout[];
|
PendingSpectreLoadouts?: ISpectreLoadout[];
|
||||||
@ -283,6 +285,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
CompletedSorties: string[];
|
CompletedSorties: string[];
|
||||||
LastSortieReward?: ILastSortieRewardClient[];
|
LastSortieReward?: ILastSortieRewardClient[];
|
||||||
LastLiteSortieReward?: ILastSortieRewardClient[];
|
LastLiteSortieReward?: ILastSortieRewardClient[];
|
||||||
|
SortieRewardAttenuation?: ISortieRewardAttenuation[];
|
||||||
Drones: IDroneClient[];
|
Drones: IDroneClient[];
|
||||||
StepSequencers: IStepSequencer[];
|
StepSequencers: IStepSequencer[];
|
||||||
ActiveAvatarImageType: string;
|
ActiveAvatarImageType: string;
|
||||||
@ -324,7 +327,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu
|
|||||||
InfestedFoundry?: IInfestedFoundryClient;
|
InfestedFoundry?: IInfestedFoundryClient;
|
||||||
BlessingCooldown?: IMongoDate;
|
BlessingCooldown?: IMongoDate;
|
||||||
CrewShipRawSalvage: ITypeCount[];
|
CrewShipRawSalvage: ITypeCount[];
|
||||||
CrewMembers: ICrewMember[];
|
CrewMembers: ICrewMemberClient[];
|
||||||
LotusCustomization: ILotusCustomization;
|
LotusCustomization: ILotusCustomization;
|
||||||
UseAdultOperatorLoadout?: boolean;
|
UseAdultOperatorLoadout?: boolean;
|
||||||
NemesisAbandonedRewards: string[];
|
NemesisAbandonedRewards: string[];
|
||||||
@ -461,32 +464,36 @@ export interface ICompletedJob {
|
|||||||
StageCompletions: number[];
|
StageCompletions: number[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICrewMember {
|
export interface ICrewMemberSkill {
|
||||||
|
Assigned: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICrewMemberSkillEfficiency {
|
||||||
|
PILOTING: ICrewMemberSkill;
|
||||||
|
GUNNERY: ICrewMemberSkill;
|
||||||
|
ENGINEERING: ICrewMemberSkill;
|
||||||
|
COMBAT: ICrewMemberSkill;
|
||||||
|
SURVIVABILITY: ICrewMemberSkill;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface ICrewMemberClient {
|
||||||
ItemType: string;
|
ItemType: string;
|
||||||
NemesisFingerprint: number;
|
NemesisFingerprint: bigint;
|
||||||
Seed: number;
|
Seed: bigint;
|
||||||
HireDate: IMongoDate;
|
AssignedRole?: number;
|
||||||
AssignedRole: number;
|
SkillEfficiency: ICrewMemberSkillEfficiency;
|
||||||
SkillEfficiency: ISkillEfficiency;
|
|
||||||
WeaponConfigIdx: number;
|
WeaponConfigIdx: number;
|
||||||
WeaponId: IOid;
|
WeaponId: IOid;
|
||||||
XP: number;
|
XP: number;
|
||||||
PowersuitType: string;
|
PowersuitType: string;
|
||||||
Configs: IItemConfig[];
|
Configs: IItemConfig[];
|
||||||
SecondInCommand: boolean;
|
SecondInCommand: boolean; // on call
|
||||||
ItemId: IOid;
|
ItemId: IOid;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISkillEfficiency {
|
export interface ICrewMemberDatabase extends Omit<ICrewMemberClient, "WeaponId" | "ItemId"> {
|
||||||
PILOTING: ICombat;
|
WeaponId: Types.ObjectId;
|
||||||
GUNNERY: ICombat;
|
_id: Types.ObjectId;
|
||||||
ENGINEERING: ICombat;
|
|
||||||
COMBAT: ICombat;
|
|
||||||
SURVIVABILITY: ICombat;
|
|
||||||
}
|
|
||||||
|
|
||||||
export interface ICombat {
|
|
||||||
Assigned: number;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export enum InventorySlot {
|
export enum InventorySlot {
|
||||||
@ -532,12 +539,12 @@ export interface ICrewShipMembersDatabase {
|
|||||||
|
|
||||||
export interface ICrewShipMemberClient {
|
export interface ICrewShipMemberClient {
|
||||||
ItemId?: IOid;
|
ItemId?: IOid;
|
||||||
NemesisFingerprint?: number;
|
NemesisFingerprint?: number | bigint;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICrewShipMemberDatabase {
|
export interface ICrewShipMemberDatabase {
|
||||||
ItemId?: Types.ObjectId;
|
ItemId?: Types.ObjectId;
|
||||||
NemesisFingerprint?: number;
|
NemesisFingerprint?: bigint;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICrewShipCustomization {
|
export interface ICrewShipCustomization {
|
||||||
@ -562,17 +569,18 @@ export type IMiscItem = ITypeCount;
|
|||||||
|
|
||||||
// inventory.CrewShips[0].Weapon
|
// inventory.CrewShips[0].Weapon
|
||||||
export interface ICrewShipWeapon {
|
export interface ICrewShipWeapon {
|
||||||
PILOT: ICrewShipPilotWeapon;
|
PILOT?: ICrewShipWeaponEmplacements;
|
||||||
PORT_GUNS: ICrewShipPortGuns;
|
PORT_GUNS?: ICrewShipWeaponEmplacements;
|
||||||
|
STARBOARD_GUNS?: ICrewShipWeaponEmplacements;
|
||||||
|
ARTILLERY?: ICrewShipWeaponEmplacements;
|
||||||
|
SCANNER?: ICrewShipWeaponEmplacements;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICrewShipPilotWeapon {
|
export interface ICrewShipWeaponEmplacements {
|
||||||
PRIMARY_A: IEquipmentSelection;
|
PRIMARY_A?: IEquipmentSelection;
|
||||||
SECONDARY_A: IEquipmentSelection;
|
PRIMARY_B?: IEquipmentSelection;
|
||||||
}
|
SECONDARY_A?: IEquipmentSelection;
|
||||||
|
SECONDARY_B?: IEquipmentSelection;
|
||||||
export interface ICrewShipPortGuns {
|
|
||||||
PRIMARY_A: IEquipmentSelection;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDiscoveredMarker {
|
export interface IDiscoveredMarker {
|
||||||
@ -668,6 +676,17 @@ export interface IInvasionChainProgress {
|
|||||||
count: number;
|
count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IInvasionProgressClient {
|
||||||
|
_id: IOid;
|
||||||
|
Delta: number;
|
||||||
|
AttackerScore: number;
|
||||||
|
DefenderScore: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
export interface IInvasionProgressDatabase extends Omit<IInvasionProgressClient, "_id"> {
|
||||||
|
invasionId: Types.ObjectId;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IKubrowPetEggClient {
|
export interface IKubrowPetEggClient {
|
||||||
ItemType: string;
|
ItemType: string;
|
||||||
ExpirationDate: IMongoDate; // seems to be set to 7 days ahead @ 0 UTC
|
ExpirationDate: IMongoDate; // seems to be set to 7 days ahead @ 0 UTC
|
||||||
@ -739,6 +758,11 @@ export interface ILastSortieRewardDatabase extends Omit<ILastSortieRewardClient,
|
|||||||
SortieId: Types.ObjectId;
|
SortieId: Types.ObjectId;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface ISortieRewardAttenuation {
|
||||||
|
Tag: string;
|
||||||
|
Atten: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface ILibraryDailyTaskInfo {
|
export interface ILibraryDailyTaskInfo {
|
||||||
EnemyTypes: string[];
|
EnemyTypes: string[];
|
||||||
EnemyLocTag: string;
|
EnemyLocTag: string;
|
||||||
@ -888,6 +912,10 @@ export interface IPendingRecipeClient
|
|||||||
CompletionDate: IMongoDate;
|
CompletionDate: IMongoDate;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IAccolades {
|
||||||
|
Heirloom?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IPendingTrade {
|
export interface IPendingTrade {
|
||||||
State: number;
|
State: number;
|
||||||
SelfReady: boolean;
|
SelfReady: boolean;
|
||||||
|
@ -1,3 +1,5 @@
|
|||||||
|
import { Types } from "mongoose";
|
||||||
|
|
||||||
export interface IAccountAndLoginResponseCommons {
|
export interface IAccountAndLoginResponseCommons {
|
||||||
DisplayName: string;
|
DisplayName: string;
|
||||||
CountryCode: string;
|
CountryCode: string;
|
||||||
@ -56,3 +58,8 @@ export interface IGroup {
|
|||||||
experiment: string;
|
experiment: string;
|
||||||
experimentGroup: string;
|
experimentGroup: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IIgnore {
|
||||||
|
ignorer: Types.ObjectId;
|
||||||
|
ignoree: Types.ObjectId;
|
||||||
|
}
|
||||||
|
@ -6,7 +6,8 @@ import {
|
|||||||
INemesisClient,
|
INemesisClient,
|
||||||
ITypeCount,
|
ITypeCount,
|
||||||
IRecentVendorPurchaseClient,
|
IRecentVendorPurchaseClient,
|
||||||
TEquipmentKey
|
TEquipmentKey,
|
||||||
|
ICrewMemberClient
|
||||||
} from "./inventoryTypes/inventoryTypes";
|
} from "./inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
export interface IPurchaseRequest {
|
export interface IPurchaseRequest {
|
||||||
@ -47,6 +48,7 @@ export type IInventoryChanges = {
|
|||||||
Nemesis?: Partial<INemesisClient>;
|
Nemesis?: Partial<INemesisClient>;
|
||||||
NewVendorPurchase?: IRecentVendorPurchaseClient; // >= 38.5.0
|
NewVendorPurchase?: IRecentVendorPurchaseClient; // >= 38.5.0
|
||||||
RecentVendorPurchases?: IRecentVendorPurchaseClient; // < 38.5.0
|
RecentVendorPurchases?: IRecentVendorPurchaseClient; // < 38.5.0
|
||||||
|
CrewMembers?: ICrewMemberClient[];
|
||||||
} & Record<
|
} & Record<
|
||||||
Exclude<
|
Exclude<
|
||||||
string,
|
string,
|
||||||
|
@ -19,7 +19,8 @@ import {
|
|||||||
ICollectibleEntry,
|
ICollectibleEntry,
|
||||||
IDiscoveredMarker,
|
IDiscoveredMarker,
|
||||||
ILockedWeaponGroupClient,
|
ILockedWeaponGroupClient,
|
||||||
ILoadOutPresets
|
ILoadOutPresets,
|
||||||
|
IInvasionProgressClient
|
||||||
} from "./inventoryTypes/inventoryTypes";
|
} from "./inventoryTypes/inventoryTypes";
|
||||||
import { IGroup } from "./loginTypes";
|
import { IGroup } from "./loginTypes";
|
||||||
|
|
||||||
@ -123,12 +124,15 @@ export type IMissionInventoryUpdateRequest = {
|
|||||||
};
|
};
|
||||||
wagerTier?: number; // the index
|
wagerTier?: number; // the index
|
||||||
creditsFee?: number; // the index
|
creditsFee?: number; // the index
|
||||||
|
InvasionProgress?: IInvasionProgressClient[];
|
||||||
} & {
|
} & {
|
||||||
[K in TEquipmentKey]?: IEquipmentClient[];
|
[K in TEquipmentKey]?: IEquipmentClient[];
|
||||||
};
|
};
|
||||||
|
|
||||||
export interface IRewardInfo {
|
export interface IRewardInfo {
|
||||||
node: string;
|
node: string;
|
||||||
|
invasionId?: string;
|
||||||
|
invasionAllyFaction?: "FC_GRINEER" | "FC_CORPUS";
|
||||||
sortieId?: string;
|
sortieId?: string;
|
||||||
sortieTag?: string;
|
sortieTag?: string;
|
||||||
sortiePrereqs?: string[];
|
sortiePrereqs?: string[];
|
||||||
|
@ -1,7 +1,13 @@
|
|||||||
import { IOid } from "@/src/types/commonTypes";
|
import { IOid } from "@/src/types/commonTypes";
|
||||||
import { IItemConfig, IOperatorConfigClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
import { IItemConfig, IOperatorConfigClient } from "@/src/types/inventoryTypes/commonInventoryTypes";
|
||||||
import { Types } from "mongoose";
|
import { Types } from "mongoose";
|
||||||
import { ILoadoutConfigClient } from "./inventoryTypes/inventoryTypes";
|
import {
|
||||||
|
ICrewShipCustomization,
|
||||||
|
ICrewShipMembersClient,
|
||||||
|
ICrewShipWeapon,
|
||||||
|
IFlavourItem,
|
||||||
|
ILoadoutConfigClient
|
||||||
|
} from "./inventoryTypes/inventoryTypes";
|
||||||
|
|
||||||
export interface ISaveLoadoutRequest {
|
export interface ISaveLoadoutRequest {
|
||||||
LoadOuts: ILoadoutClient;
|
LoadOuts: ILoadoutClient;
|
||||||
@ -51,7 +57,16 @@ export interface IItemEntry {
|
|||||||
|
|
||||||
export type IConfigEntry = {
|
export type IConfigEntry = {
|
||||||
[configId in "0" | "1" | "2" | "3" | "4" | "5"]: IItemConfig;
|
[configId in "0" | "1" | "2" | "3" | "4" | "5"]: IItemConfig;
|
||||||
} & { Favorite?: boolean; IsNew?: boolean };
|
} & {
|
||||||
|
Favorite?: boolean;
|
||||||
|
IsNew?: boolean;
|
||||||
|
// Railjack
|
||||||
|
ItemName?: string;
|
||||||
|
RailjackImage?: IFlavourItem;
|
||||||
|
Customization?: ICrewShipCustomization;
|
||||||
|
Weapon?: ICrewShipWeapon;
|
||||||
|
CrewMembers?: ICrewShipMembersClient;
|
||||||
|
};
|
||||||
|
|
||||||
export type ILoadoutClient = Omit<ILoadoutDatabase, "_id" | "loadoutOwnerId">;
|
export type ILoadoutClient = Omit<ILoadoutDatabase, "_id" | "loadoutOwnerId">;
|
||||||
|
|
||||||
|
@ -32,7 +32,7 @@ export interface IVendorInfo {
|
|||||||
TypeName: string;
|
TypeName: string;
|
||||||
ItemManifest: IItemManifest[];
|
ItemManifest: IItemManifest[];
|
||||||
PropertyTextHash?: string;
|
PropertyTextHash?: string;
|
||||||
RandomSeedType?: "VRST_WEAPON";
|
RandomSeedType?: string;
|
||||||
RequiredGoalTag?: string;
|
RequiredGoalTag?: string;
|
||||||
WeaponUpgradeValueAttenuationExponent?: number;
|
WeaponUpgradeValueAttenuationExponent?: number;
|
||||||
Expiry: IMongoDate; // Either a date in the distant future or a period in milliseconds for preprocessing.
|
Expiry: IMongoDate; // Either a date in the distant future or a period in milliseconds for preprocessing.
|
||||||
|
@ -103,7 +103,7 @@ export interface ILiteSortie {
|
|||||||
Expiry: IMongoDate;
|
Expiry: IMongoDate;
|
||||||
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards";
|
Reward: "/Lotus/Types/Game/MissionDecks/ArchonSortieRewards";
|
||||||
Seed: number;
|
Seed: number;
|
||||||
Boss: string; // "SORTIE_BOSS_AMAR" | "SORTIE_BOSS_NIRA" | "SORTIE_BOSS_BOREAL"
|
Boss: "SORTIE_BOSS_AMAR" | "SORTIE_BOSS_NIRA" | "SORTIE_BOSS_BOREAL";
|
||||||
Missions: {
|
Missions: {
|
||||||
missionType: string;
|
missionType: string;
|
||||||
node: string;
|
node: string;
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
|
// Misnomer: We have concurrency, not parallelism - oh well!
|
||||||
export const parallelForeach = async <T>(data: T[], op: (datum: T) => Promise<void>): Promise<void> => {
|
export const parallelForeach = async <T>(data: T[], op: (datum: T) => Promise<void>): Promise<void> => {
|
||||||
const promises: Promise<void>[] = [];
|
const promises: Promise<void>[] = [];
|
||||||
for (const datum of data) {
|
for (const datum of data) {
|
||||||
|
@ -1092,5 +1092,11 @@
|
|||||||
"/Lotus/Types/Game/CrewShip/GrineerDestroyer/GrineerDestroyerAvatar",
|
"/Lotus/Types/Game/CrewShip/GrineerDestroyer/GrineerDestroyerAvatar",
|
||||||
"/Lotus/Types/LevelObjects/Zariman/ZarLootCrateUltraRare",
|
"/Lotus/Types/LevelObjects/Zariman/ZarLootCrateUltraRare",
|
||||||
"/Lotus/Objects/DomestikDrone/GrineerOceanDomestikDroneMover",
|
"/Lotus/Objects/DomestikDrone/GrineerOceanDomestikDroneMover",
|
||||||
"/Lotus/Types/Gameplay/1999Wf/Extermination/SupplyCrate"
|
"/Lotus/Types/Gameplay/1999Wf/Extermination/SupplyCrate",
|
||||||
|
"/Lotus/Objects/Orokin/Props/CollectibleSeriesOne",
|
||||||
|
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLamp",
|
||||||
|
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLampLarge",
|
||||||
|
"/Lotus/Types/LevelObjects/InfestedPumpkinCocoonLampSmall",
|
||||||
|
"/Lotus/Types/LevelObjects/InfestedPumpkinExplosiveTotem",
|
||||||
|
"/Lotus/Types/Enemies/Orokin/OrokinMoaBipedAvatar"
|
||||||
]
|
]
|
||||||
|
@ -1,133 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "60ad3b6ec96976e97d227e19"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Hubs/PerrinSequenceWeaponVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Weapons/Corpus/BoardExec/Primary/CrpBEFerrox/CrpBEFerrox",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 40,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/GranumBucks",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"LocTagRandSeed": 4383829823946960400,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9488"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Weapons/Corpus/Melee/CrpBriefcaseScythe/CrpBriefcaseScythe",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 40,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/GranumBucks",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"LocTagRandSeed": 7952272124248276000,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9489"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Weapons/Corpus/Melee/CrpBriefcase2HKatana/CrpBriefcase2HKatana",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 40,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/GranumBucks",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"LocTagRandSeed": 465952672558014140,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e948a"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Weapons/Tenno/Melee/Swords/CrpBigSlash/CrpBigSlash",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 40,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/GranumBucks",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"LocTagRandSeed": 8342430883077507000,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e948b"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Weapons/Corpus/Melee/ShieldAndSword/CrpHammerShield/CrpHammerShield",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 40,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/GranumBucks",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"LocTagRandSeed": 7441523153174502000,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e948c"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "34F8CF1DFF745F0D67433A5EF0A03E70",
|
|
||||||
"RandomSeedType": "VRST_WEAPON",
|
|
||||||
"WeaponUpgradeValueAttenuationExponent": 2.25,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -487,6 +487,7 @@ function updateInventory() {
|
|||||||
a.href = "#";
|
a.href = "#";
|
||||||
a.onclick = function (event) {
|
a.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
document.getElementById(category + "-list").removeChild(tr);
|
||||||
disposeOfGear(category, item.ItemId.$oid);
|
disposeOfGear(category, item.ItemId.$oid);
|
||||||
};
|
};
|
||||||
a.title = loc("code_remove");
|
a.title = loc("code_remove");
|
||||||
@ -683,6 +684,7 @@ function updateInventory() {
|
|||||||
a.href = "#";
|
a.href = "#";
|
||||||
a.onclick = function (event) {
|
a.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
document.getElementById("riven-list").removeChild(tr);
|
||||||
disposeOfGear("Upgrades", item.ItemId.$oid);
|
disposeOfGear("Upgrades", item.ItemId.$oid);
|
||||||
};
|
};
|
||||||
a.title = loc("code_remove");
|
a.title = loc("code_remove");
|
||||||
@ -723,6 +725,7 @@ function updateInventory() {
|
|||||||
a.href = "#";
|
a.href = "#";
|
||||||
a.onclick = function (event) {
|
a.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
document.getElementById("mods-list").removeChild(tr);
|
||||||
disposeOfGear("Upgrades", item.ItemId.$oid);
|
disposeOfGear("Upgrades", item.ItemId.$oid);
|
||||||
};
|
};
|
||||||
a.title = loc("code_remove");
|
a.title = loc("code_remove");
|
||||||
@ -765,6 +768,7 @@ function updateInventory() {
|
|||||||
a.href = "#";
|
a.href = "#";
|
||||||
a.onclick = function (event) {
|
a.onclick = function (event) {
|
||||||
event.preventDefault();
|
event.preventDefault();
|
||||||
|
document.getElementById("mods-list").removeChild(tr);
|
||||||
disposeOfItems("Upgrades", item.ItemType, item.ItemCount);
|
disposeOfItems("Upgrades", item.ItemType, item.ItemCount);
|
||||||
};
|
};
|
||||||
a.title = loc("code_remove");
|
a.title = loc("code_remove");
|
||||||
@ -1097,8 +1101,6 @@ function disposeOfGear(category, oid) {
|
|||||||
url: "/api/sell.php?" + window.authz,
|
url: "/api/sell.php?" + window.authz,
|
||||||
contentType: "text/plain",
|
contentType: "text/plain",
|
||||||
data: JSON.stringify(data)
|
data: JSON.stringify(data)
|
||||||
}).done(function () {
|
|
||||||
updateInventory();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1120,8 +1122,6 @@ function disposeOfItems(category, type, count) {
|
|||||||
url: "/api/sell.php?" + window.authz,
|
url: "/api/sell.php?" + window.authz,
|
||||||
contentType: "text/plain",
|
contentType: "text/plain",
|
||||||
data: JSON.stringify(data)
|
data: JSON.stringify(data)
|
||||||
}).done(function () {
|
|
||||||
updateInventory();
|
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
@ -1260,6 +1260,8 @@ function doAcquireMod() {
|
|||||||
$("#mod-to-acquire").addClass("is-invalid").focus();
|
$("#mod-to-acquire").addClass("is-invalid").focus();
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
const count = parseInt($("#mod-count").val());
|
||||||
|
if (count != 0) {
|
||||||
revalidateAuthz(() => {
|
revalidateAuthz(() => {
|
||||||
$.post({
|
$.post({
|
||||||
url: "/custom/addItems?" + window.authz,
|
url: "/custom/addItems?" + window.authz,
|
||||||
@ -1267,15 +1269,20 @@ function doAcquireMod() {
|
|||||||
data: JSON.stringify([
|
data: JSON.stringify([
|
||||||
{
|
{
|
||||||
ItemType: uniqueName,
|
ItemType: uniqueName,
|
||||||
ItemCount: parseInt($("#mod-count").val())
|
ItemCount: count
|
||||||
}
|
}
|
||||||
])
|
])
|
||||||
}).done(function () {
|
}).done(function () {
|
||||||
document.getElementById("mod-to-acquire").value = "";
|
if (count > 0) {
|
||||||
|
toast(loc("code_succAdded"));
|
||||||
|
} else {
|
||||||
|
toast(loc("code_succRemoved"));
|
||||||
|
}
|
||||||
updateInventory();
|
updateInventory();
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
|
const uiConfigs = [...$("#server-settings input[id]")].map(x => x.id);
|
||||||
|
|
||||||
@ -1315,7 +1322,7 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
|
|||||||
interval = setInterval(() => {
|
interval = setInterval(() => {
|
||||||
if (window.authz) {
|
if (window.authz) {
|
||||||
clearInterval(interval);
|
clearInterval(interval);
|
||||||
fetch("/custom/config?" + window.authz).then(res => {
|
fetch("/custom/config?" + window.authz).then(async res => {
|
||||||
if (res.status == 200) {
|
if (res.status == 200) {
|
||||||
$("#server-settings-no-perms").addClass("d-none");
|
$("#server-settings-no-perms").addClass("d-none");
|
||||||
$("#server-settings").removeClass("d-none");
|
$("#server-settings").removeClass("d-none");
|
||||||
@ -1334,10 +1341,18 @@ single.getRoute("/webui/cheats").on("beforeload", function () {
|
|||||||
}
|
}
|
||||||
})
|
})
|
||||||
);
|
);
|
||||||
|
} else {
|
||||||
|
if ((await res.text()) == "Log-in expired") {
|
||||||
|
revalidateAuthz(() => {
|
||||||
|
if (single.getCurrentPath() == "/webui/cheats") {
|
||||||
|
single.loadRoute("/webui/cheats");
|
||||||
|
}
|
||||||
|
});
|
||||||
} else {
|
} else {
|
||||||
$("#server-settings-no-perms").removeClass("d-none");
|
$("#server-settings-no-perms").removeClass("d-none");
|
||||||
$("#server-settings").addClass("d-none");
|
$("#server-settings").addClass("d-none");
|
||||||
}
|
}
|
||||||
|
}
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}, 10);
|
}, 10);
|
||||||
|
@ -138,7 +138,7 @@ dict = {
|
|||||||
cheats_noArgonCrystalDecay: `Argon-Kristalle verschwinden niemals`,
|
cheats_noArgonCrystalDecay: `Argon-Kristalle verschwinden niemals`,
|
||||||
cheats_noMasteryRankUpCooldown: `Keine Wartezeit beim Meisterschaftsrangaufstieg`,
|
cheats_noMasteryRankUpCooldown: `Keine Wartezeit beim Meisterschaftsrangaufstieg`,
|
||||||
cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`,
|
cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`,
|
||||||
cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`,
|
cheats_noDeathMarks: `Keine Todesmarkierungen`,
|
||||||
cheats_noKimCooldowns: `Keine Wartezeit bei KIM`,
|
cheats_noKimCooldowns: `Keine Wartezeit bei KIM`,
|
||||||
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
|
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
|
||||||
cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,
|
cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user