forked from OpenWF/SpaceNinjaServer
Compare commits
6 Commits
translatio
...
main
Author | SHA1 | Date | |
---|---|---|---|
b98a88b700 | |||
6023f1c113 | |||
c6dd8bfb81 | |||
3053112428 | |||
f448d03880 | |||
d00fbed46f |
8
package-lock.json
generated
8
package-lock.json
generated
@ -18,7 +18,7 @@
|
|||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": "^5.5",
|
||||||
"warframe-public-export-plus": "^0.5.66",
|
"warframe-public-export-plus": "^0.5.67",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
@ -3814,9 +3814,9 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/warframe-public-export-plus": {
|
"node_modules/warframe-public-export-plus": {
|
||||||
"version": "0.5.66",
|
"version": "0.5.67",
|
||||||
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.66.tgz",
|
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.67.tgz",
|
||||||
"integrity": "sha512-AU7XQA96OfYrLm2RioCwDjjdI3IrsmUiqebXyE+bpM0iST+4x/NHu8LTRT4Oygfo/2OBtDYhib7G6re0EeAe5g=="
|
"integrity": "sha512-LsnZD2E5PTA+5MK9kDGvM/hFDtg8sb0EwQ4hKH5ILqrSgz30a9W8785v77RSsL1AEVF8dfb/lZcSTCJq1DZHzQ=="
|
||||||
},
|
},
|
||||||
"node_modules/warframe-riven-info": {
|
"node_modules/warframe-riven-info": {
|
||||||
"version": "0.1.2",
|
"version": "0.1.2",
|
||||||
|
@ -25,7 +25,7 @@
|
|||||||
"morgan": "^1.10.0",
|
"morgan": "^1.10.0",
|
||||||
"ncp": "^2.0.0",
|
"ncp": "^2.0.0",
|
||||||
"typescript": "^5.5",
|
"typescript": "^5.5",
|
||||||
"warframe-public-export-plus": "^0.5.66",
|
"warframe-public-export-plus": "^0.5.67",
|
||||||
"warframe-riven-info": "^0.1.2",
|
"warframe-riven-info": "^0.1.2",
|
||||||
"winston": "^3.17.0",
|
"winston": "^3.17.0",
|
||||||
"winston-daily-rotate-file": "^5.0.0"
|
"winston-daily-rotate-file": "^5.0.0"
|
||||||
|
@ -24,7 +24,7 @@ export const saveDialogueController: RequestHandler = async (req, res) => {
|
|||||||
inventory.DialogueHistory.Dialogues ??= [];
|
inventory.DialogueHistory.Dialogues ??= [];
|
||||||
const dialogue = getDialogue(inventory, request.DialogueName);
|
const dialogue = getDialogue(inventory, request.DialogueName);
|
||||||
dialogue.Rank = request.Rank;
|
dialogue.Rank = request.Rank;
|
||||||
dialogue.Chemistry = request.Chemistry;
|
dialogue.Chemistry += request.Chemistry;
|
||||||
dialogue.QueuedDialogues = request.QueuedDialogues;
|
dialogue.QueuedDialogues = request.QueuedDialogues;
|
||||||
for (const bool of request.Booleans) {
|
for (const bool of request.Booleans) {
|
||||||
dialogue.Booleans.push(bool);
|
dialogue.Booleans.push(bool);
|
||||||
|
@ -1,9 +1,14 @@
|
|||||||
// First, init config.
|
// First, init config.
|
||||||
import { config, loadConfig } from "@/src/services/configService";
|
import { config, loadConfig } from "@/src/services/configService";
|
||||||
|
import fs from "fs";
|
||||||
try {
|
try {
|
||||||
loadConfig();
|
loadConfig();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
console.log("ERROR: Failed to load config.json. You can copy config.json.example to create your config.json.");
|
if (fs.existsSync("config.json")) {
|
||||||
|
console.log("Failed to load config.json: " + (e as Error).message);
|
||||||
|
} else {
|
||||||
|
console.log("Failed to load config.json. You can copy config.json.example to create your config.json.");
|
||||||
|
}
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -13,7 +13,7 @@ fs.watchFile(configPath, () => {
|
|||||||
try {
|
try {
|
||||||
loadConfig();
|
loadConfig();
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
logger.error("Failed to reload config.json. Did you delete it?! Execution cannot continue.");
|
logger.error("FATAL ERROR: Config failed to be reloaded: " + (e as Error).message);
|
||||||
process.exit(1);
|
process.exit(1);
|
||||||
}
|
}
|
||||||
validateConfig();
|
validateConfig();
|
||||||
|
@ -66,15 +66,7 @@ import {
|
|||||||
} from "@/src/helpers/nemesisHelpers";
|
} from "@/src/helpers/nemesisHelpers";
|
||||||
import { Loadout } from "../models/inventoryModels/loadoutModel";
|
import { Loadout } from "../models/inventoryModels/loadoutModel";
|
||||||
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
|
import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes";
|
||||||
import {
|
import { getLiteSortie, getSortie, idToBountyCycle, idToDay, idToWeek, pushClassicBounties } from "./worldStateService";
|
||||||
getLiteSortie,
|
|
||||||
getSortie,
|
|
||||||
getWorldState,
|
|
||||||
idToBountyCycle,
|
|
||||||
idToDay,
|
|
||||||
idToWeek,
|
|
||||||
pushClassicBounties
|
|
||||||
} from "./worldStateService";
|
|
||||||
import { config } from "./configService";
|
import { config } from "./configService";
|
||||||
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json";
|
||||||
import { ISyndicateMissionInfo } from "../types/worldStateTypes";
|
import { ISyndicateMissionInfo } from "../types/worldStateTypes";
|
||||||
@ -1266,9 +1258,9 @@ export const addMissionRewards = async (
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (rewardInfo.challengeMissionId) {
|
if (rewardInfo.challengeMissionId) {
|
||||||
const [syndicateTag, tierStr, chemistryStr] = rewardInfo.challengeMissionId.split("_");
|
const [syndicateTag, tierStr, chemistryBuddyStr] = rewardInfo.challengeMissionId.split("_");
|
||||||
const tier = Number(tierStr);
|
const tier = Number(tierStr);
|
||||||
const chemistry = Number(chemistryStr);
|
const chemistryBuddy = Number(chemistryBuddyStr);
|
||||||
const isSteelPath = missions?.Tier;
|
const isSteelPath = missions?.Tier;
|
||||||
if (syndicateTag === "ZarimanSyndicate") {
|
if (syndicateTag === "ZarimanSyndicate") {
|
||||||
let medallionAmount = tier + 1;
|
let medallionAmount = tier + 1;
|
||||||
@ -1285,22 +1277,19 @@ export const addMissionRewards = async (
|
|||||||
if (isSteelPath) standingAmount *= 1.5;
|
if (isSteelPath) standingAmount *= 1.5;
|
||||||
addStanding(inventory, syndicateTag, standingAmount, AffiliationMods);
|
addStanding(inventory, syndicateTag, standingAmount, AffiliationMods);
|
||||||
}
|
}
|
||||||
if (syndicateTag == "HexSyndicate" && chemistry && tier < 6) {
|
if (syndicateTag == "HexSyndicate" && tier < 6) {
|
||||||
const seed = getWorldState().SyndicateMissions.find(x => x.Tag == "HexSyndicate")!.Seed;
|
const buddy = chemistryBuddies[chemistryBuddy];
|
||||||
const { nodes, buddies } = getHexBounties(seed);
|
const dialogue = getDialogue(inventory, buddy);
|
||||||
const buddy = buddies[tier];
|
if (Date.now() >= dialogue.BountyChemExpiry.getTime()) {
|
||||||
logger.debug(`Hex seed is ${seed}, giving chemistry for ${buddy}`);
|
logger.debug(`Giving 20 chemistry for ${buddy}`);
|
||||||
if (missions?.Tag != nodes[tier]) {
|
|
||||||
logger.warn(
|
|
||||||
`Uh-oh, tier ${tier} bounty should've been on ${nodes[tier]} but you were just on ${missions?.Tag}`
|
|
||||||
);
|
|
||||||
}
|
|
||||||
const tomorrowAt0Utc = config.noKimCooldowns
|
const tomorrowAt0Utc = config.noKimCooldowns
|
||||||
? Date.now()
|
? Date.now()
|
||||||
: (Math.trunc(Date.now() / 86400_000) + 1) * 86400_000;
|
: (Math.trunc(Date.now() / 86400_000) + 1) * 86400_000;
|
||||||
const dialogue = getDialogue(inventory, buddy);
|
dialogue.Chemistry += 20;
|
||||||
dialogue.Chemistry += chemistry;
|
|
||||||
dialogue.BountyChemExpiry = new Date(tomorrowAt0Utc);
|
dialogue.BountyChemExpiry = new Date(tomorrowAt0Utc);
|
||||||
|
} else {
|
||||||
|
logger.debug(`Already got today's chemistry for ${buddy}`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if (isSteelPath) {
|
if (isSteelPath) {
|
||||||
await addItem(inventory, "/Lotus/Types/Items/MiscItems/SteelEssence", 1);
|
await addItem(inventory, "/Lotus/Types/Items/MiscItems/SteelEssence", 1);
|
||||||
@ -1864,7 +1853,16 @@ const libraryPersonalTargetToAvatar: Record<string, string> = {
|
|||||||
"/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/NullifySpacemanAvatar"
|
"/Lotus/Types/Enemies/Corpus/Spaceman/AIWeek/NullifySpacemanAvatar"
|
||||||
};
|
};
|
||||||
|
|
||||||
const node_excluded_buddies: Record<string, string> = {
|
const chemistryBuddies: readonly string[] = [
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue",
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/AoiDialogue_rom.dialogue",
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue",
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/EleanorDialogue_rom.dialogue",
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue",
|
||||||
|
"/Lotus/Types/Gameplay/1999Wf/Dialogue/QuincyDialogue_rom.dialogue"
|
||||||
|
];
|
||||||
|
|
||||||
|
/*const node_excluded_buddies: Record<string, string> = {
|
||||||
SolNode856: "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue",
|
SolNode856: "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue",
|
||||||
SolNode852: "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue",
|
SolNode852: "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue",
|
||||||
SolNode851: "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue",
|
SolNode851: "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue",
|
||||||
@ -1914,4 +1912,4 @@ const getHexBounties = (seed: number): { nodes: string[]; buddies: string[] } =>
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
return { nodes, buddies };
|
return { nodes, buddies };
|
||||||
};
|
};*/
|
||||||
|
@ -6,7 +6,7 @@ import { mixSeeds, SRng } from "@/src/services/rngService";
|
|||||||
import { IMongoDate } from "@/src/types/commonTypes";
|
import { IMongoDate } from "@/src/types/commonTypes";
|
||||||
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
|
import { IItemManifest, IVendorInfo, IVendorManifest } from "@/src/types/vendorTypes";
|
||||||
import { logger } from "@/src/utils/logger";
|
import { logger } from "@/src/utils/logger";
|
||||||
import { ExportVendors, IRange, IVendor } from "warframe-public-export-plus";
|
import { ExportVendors, IRange, IVendor, IVendorOffer } from "warframe-public-export-plus";
|
||||||
|
|
||||||
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
import ArchimedeanVendorManifest from "@/static/fixed_responses/getVendorInfo/ArchimedeanVendorManifest.json";
|
||||||
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
|
import DeimosEntratiFragmentVendorProductsManifest from "@/static/fixed_responses/getVendorInfo/DeimosEntratiFragmentVendorProductsManifest.json";
|
||||||
@ -17,18 +17,14 @@ import DeimosHivemindCommisionsManifestTokenVendor from "@/static/fixed_response
|
|||||||
import DeimosHivemindCommisionsManifestWeaponsmith from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestWeaponsmith.json";
|
import DeimosHivemindCommisionsManifestWeaponsmith from "@/static/fixed_responses/getVendorInfo/DeimosHivemindCommisionsManifestWeaponsmith.json";
|
||||||
import DeimosHivemindTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosHivemindTokenVendorManifest.json";
|
import DeimosHivemindTokenVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosHivemindTokenVendorManifest.json";
|
||||||
import DeimosPetVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosPetVendorManifest.json";
|
import DeimosPetVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosPetVendorManifest.json";
|
||||||
import DeimosProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/DeimosProspectorVendorManifest.json";
|
|
||||||
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
|
import DuviriAcrithisVendorManifest from "@/static/fixed_responses/getVendorInfo/DuviriAcrithisVendorManifest.json";
|
||||||
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
|
import EntratiLabsEntratiLabsCommisionsManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabsCommisionsManifest.json";
|
||||||
import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
|
import EntratiLabsEntratiLabVendorManifest from "@/static/fixed_responses/getVendorInfo/EntratiLabsEntratiLabVendorManifest.json";
|
||||||
import HubsIronwakeDondaVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsIronwakeDondaVendorManifest.json";
|
|
||||||
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
|
import HubsRailjackCrewMemberVendorManifest from "@/static/fixed_responses/getVendorInfo/HubsRailjackCrewMemberVendorManifest.json";
|
||||||
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
|
import MaskSalesmanManifest from "@/static/fixed_responses/getVendorInfo/MaskSalesmanManifest.json";
|
||||||
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
|
import Nova1999ConquestShopManifest from "@/static/fixed_responses/getVendorInfo/Nova1999ConquestShopManifest.json";
|
||||||
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
|
import OstronPetVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronPetVendorManifest.json";
|
||||||
import OstronProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/OstronProspectorVendorManifest.json";
|
|
||||||
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
|
import SolarisDebtTokenVendorRepossessionsManifest from "@/static/fixed_responses/getVendorInfo/SolarisDebtTokenVendorRepossessionsManifest.json";
|
||||||
import SolarisProspectorVendorManifest from "@/static/fixed_responses/getVendorInfo/SolarisProspectorVendorManifest.json";
|
|
||||||
import Temple1999VendorManifest from "@/static/fixed_responses/getVendorInfo/Temple1999VendorManifest.json";
|
import Temple1999VendorManifest from "@/static/fixed_responses/getVendorInfo/Temple1999VendorManifest.json";
|
||||||
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
|
import TeshinHardModeVendorManifest from "@/static/fixed_responses/getVendorInfo/TeshinHardModeVendorManifest.json";
|
||||||
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
import ZarimanCommisionsManifestArchimedean from "@/static/fixed_responses/getVendorInfo/ZarimanCommisionsManifestArchimedean.json";
|
||||||
@ -43,18 +39,14 @@ const rawVendorManifests: IVendorManifest[] = [
|
|||||||
DeimosHivemindCommisionsManifestWeaponsmith,
|
DeimosHivemindCommisionsManifestWeaponsmith,
|
||||||
DeimosHivemindTokenVendorManifest,
|
DeimosHivemindTokenVendorManifest,
|
||||||
DeimosPetVendorManifest,
|
DeimosPetVendorManifest,
|
||||||
DeimosProspectorVendorManifest,
|
|
||||||
DuviriAcrithisVendorManifest,
|
DuviriAcrithisVendorManifest,
|
||||||
EntratiLabsEntratiLabsCommisionsManifest,
|
EntratiLabsEntratiLabsCommisionsManifest,
|
||||||
EntratiLabsEntratiLabVendorManifest,
|
EntratiLabsEntratiLabVendorManifest,
|
||||||
HubsIronwakeDondaVendorManifest, // uses preprocessing
|
|
||||||
HubsRailjackCrewMemberVendorManifest,
|
HubsRailjackCrewMemberVendorManifest,
|
||||||
MaskSalesmanManifest,
|
MaskSalesmanManifest,
|
||||||
Nova1999ConquestShopManifest,
|
Nova1999ConquestShopManifest,
|
||||||
OstronPetVendorManifest,
|
OstronPetVendorManifest,
|
||||||
OstronProspectorVendorManifest,
|
|
||||||
SolarisDebtTokenVendorRepossessionsManifest,
|
SolarisDebtTokenVendorRepossessionsManifest,
|
||||||
SolarisProspectorVendorManifest,
|
|
||||||
Temple1999VendorManifest,
|
Temple1999VendorManifest,
|
||||||
TeshinHardModeVendorManifest, // uses preprocessing
|
TeshinHardModeVendorManifest, // uses preprocessing
|
||||||
ZarimanCommisionsManifestArchimedean
|
ZarimanCommisionsManifestArchimedean
|
||||||
@ -83,10 +75,6 @@ const generatableVendors: IGeneratableVendorInfo[] = [
|
|||||||
cycleOffset: 1744934400_000,
|
cycleOffset: 1744934400_000,
|
||||||
cycleDuration: 4 * unixTimesInMs.day
|
cycleDuration: 4 * unixTimesInMs.day
|
||||||
}
|
}
|
||||||
// {
|
|
||||||
// _id: { $oid: "5dbb4c41e966f7886c3ce939" },
|
|
||||||
// TypeName: "/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest"
|
|
||||||
// }
|
|
||||||
];
|
];
|
||||||
|
|
||||||
const getVendorOid = (typeName: string): string => {
|
const getVendorOid = (typeName: string): string => {
|
||||||
@ -228,6 +216,22 @@ const toRange = (value: IRange | number): IRange => {
|
|||||||
return value;
|
return value;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
const getCycleDurationRange = (manifest: IVendor): IRange | undefined => {
|
||||||
|
const res: IRange = { minValue: Number.MAX_SAFE_INTEGER, maxValue: 0 };
|
||||||
|
for (const offer of manifest.items) {
|
||||||
|
if (offer.durationHours) {
|
||||||
|
const range = toRange(offer.durationHours);
|
||||||
|
if (res.minValue > range.minValue) {
|
||||||
|
res.minValue = range.minValue;
|
||||||
|
}
|
||||||
|
if (res.maxValue < range.maxValue) {
|
||||||
|
res.maxValue = range.maxValue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return res.maxValue != 0 ? res : undefined;
|
||||||
|
};
|
||||||
|
|
||||||
const vendorManifestCache: Record<string, IVendorManifest> = {};
|
const vendorManifestCache: Record<string, IVendorManifest> = {};
|
||||||
|
|
||||||
const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifest => {
|
const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorManifest => {
|
||||||
@ -244,10 +248,16 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
}
|
}
|
||||||
const cacheEntry = vendorManifestCache[vendorInfo.TypeName];
|
const cacheEntry = vendorManifestCache[vendorInfo.TypeName];
|
||||||
const info = cacheEntry.VendorInfo;
|
const info = cacheEntry.VendorInfo;
|
||||||
if (Date.now() >= parseInt(info.Expiry.$date.$numberLong)) {
|
const manifest = ExportVendors[vendorInfo.TypeName];
|
||||||
|
const cycleDurationRange = getCycleDurationRange(manifest);
|
||||||
|
let now = Date.now();
|
||||||
|
if (cycleDurationRange && cycleDurationRange.minValue != cycleDurationRange.maxValue) {
|
||||||
|
now -= (cycleDurationRange.maxValue - 1) * unixTimesInMs.hour;
|
||||||
|
}
|
||||||
|
while (Date.now() >= parseInt(info.Expiry.$date.$numberLong)) {
|
||||||
// Remove expired offers
|
// Remove expired offers
|
||||||
for (let i = 0; i != info.ItemManifest.length; ) {
|
for (let i = 0; i != info.ItemManifest.length; ) {
|
||||||
if (Date.now() >= parseInt(info.ItemManifest[i].Expiry.$date.$numberLong)) {
|
if (now >= parseInt(info.ItemManifest[i].Expiry.$date.$numberLong)) {
|
||||||
info.ItemManifest.splice(i, 1);
|
info.ItemManifest.splice(i, 1);
|
||||||
} else {
|
} else {
|
||||||
++i;
|
++i;
|
||||||
@ -258,16 +268,10 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
const vendorSeed = parseInt(vendorInfo._id.$oid.substring(16), 16);
|
const vendorSeed = parseInt(vendorInfo._id.$oid.substring(16), 16);
|
||||||
const cycleOffset = vendorInfo.cycleOffset ?? 1734307200_000;
|
const cycleOffset = vendorInfo.cycleOffset ?? 1734307200_000;
|
||||||
const cycleDuration = vendorInfo.cycleDuration;
|
const cycleDuration = vendorInfo.cycleDuration;
|
||||||
const cycleIndex = Math.trunc((Date.now() - cycleOffset) / cycleDuration);
|
const cycleIndex = Math.trunc((now - cycleOffset) / cycleDuration);
|
||||||
const rng = new SRng(mixSeeds(vendorSeed, cycleIndex));
|
const rng = new SRng(mixSeeds(vendorSeed, cycleIndex));
|
||||||
const manifest = ExportVendors[vendorInfo.TypeName];
|
const offersToAdd: IVendorOffer[] = [];
|
||||||
const offersToAdd = [];
|
if (!manifest.isOneBinPerCycle) {
|
||||||
if (
|
|
||||||
manifest.numItems &&
|
|
||||||
(manifest.numItems.minValue != manifest.numItems.maxValue ||
|
|
||||||
manifest.items.length != manifest.numItems.minValue) &&
|
|
||||||
!manifest.isOneBinPerCycle
|
|
||||||
) {
|
|
||||||
const remainingItemCapacity: Record<string, number> = {};
|
const remainingItemCapacity: Record<string, number> = {};
|
||||||
for (const item of manifest.items) {
|
for (const item of manifest.items) {
|
||||||
remainingItemCapacity[item.storeItem] = 1 + item.duplicates;
|
remainingItemCapacity[item.storeItem] = 1 + item.duplicates;
|
||||||
@ -275,6 +279,7 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
for (const offer of info.ItemManifest) {
|
for (const offer of info.ItemManifest) {
|
||||||
remainingItemCapacity[offer.StoreItem] -= 1;
|
remainingItemCapacity[offer.StoreItem] -= 1;
|
||||||
}
|
}
|
||||||
|
if (manifest.numItems && manifest.items.length != manifest.numItems.minValue) {
|
||||||
const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
|
const numItemsTarget = rng.randomInt(manifest.numItems.minValue, manifest.numItems.maxValue);
|
||||||
while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) {
|
while (info.ItemManifest.length + offersToAdd.length < numItemsTarget) {
|
||||||
// TODO: Consider per-bin item limits
|
// TODO: Consider per-bin item limits
|
||||||
@ -286,20 +291,36 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
let binThisCycle;
|
for (const item of manifest.items) {
|
||||||
if (manifest.isOneBinPerCycle) {
|
if (!item.alwaysOffered && remainingItemCapacity[item.storeItem] != 0) {
|
||||||
binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
|
remainingItemCapacity[item.storeItem] -= 1;
|
||||||
|
offersToAdd.push(item);
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
for (const e of Object.entries(remainingItemCapacity)) {
|
||||||
|
const item = manifest.items.find(x => x.storeItem == e[0])!;
|
||||||
|
if (!item.alwaysOffered) {
|
||||||
|
while (e[1] != 0) {
|
||||||
|
e[1] -= 1;
|
||||||
|
offersToAdd.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
for (const item of manifest.items) {
|
||||||
|
if (item.alwaysOffered && remainingItemCapacity[item.storeItem] != 0) {
|
||||||
|
remainingItemCapacity[item.storeItem] -= 1;
|
||||||
|
offersToAdd.push(item);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
offersToAdd.reverse();
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
const binThisCycle = cycleIndex % 2; // Note: May want to auto-compute the bin size, but this is only used for coda weapons right now.
|
||||||
for (const rawItem of manifest.items) {
|
for (const rawItem of manifest.items) {
|
||||||
if (!manifest.isOneBinPerCycle || rawItem.bin == binThisCycle) {
|
if (rawItem.bin == binThisCycle) {
|
||||||
offersToAdd.push(rawItem);
|
offersToAdd.push(rawItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// For most vendors, the offers seem to roughly be in reverse order from the manifest. Coda weapons are an odd exception.
|
|
||||||
if (!manifest.isOneBinPerCycle) {
|
|
||||||
offersToAdd.reverse();
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
const cycleStart = cycleOffset + cycleIndex * cycleDuration;
|
const cycleStart = cycleOffset + cycleIndex * cycleDuration;
|
||||||
for (const rawItem of offersToAdd) {
|
for (const rawItem of offersToAdd) {
|
||||||
@ -311,7 +332,7 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
StoreItem: rawItem.storeItem,
|
StoreItem: rawItem.storeItem,
|
||||||
ItemPrices: rawItem.itemPrices?.map(itemPrice => ({ ...itemPrice, ProductCategory: "MiscItems" })),
|
ItemPrices: rawItem.itemPrices?.map(itemPrice => ({ ...itemPrice, ProductCategory: "MiscItems" })),
|
||||||
Bin: "BIN_" + rawItem.bin,
|
Bin: "BIN_" + rawItem.bin,
|
||||||
QuantityMultiplier: 1,
|
QuantityMultiplier: rawItem.quantity,
|
||||||
Expiry: { $date: { $numberLong: expiry.toString() } },
|
Expiry: { $date: { $numberLong: expiry.toString() } },
|
||||||
AllowMultipurchase: false,
|
AllowMultipurchase: false,
|
||||||
Id: {
|
Id: {
|
||||||
@ -371,6 +392,8 @@ const generateVendorManifest = (vendorInfo: IGeneratableVendorInfo): IVendorMani
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
info.Expiry.$date.$numberLong = soonestOfferExpiry.toString();
|
info.Expiry.$date.$numberLong = soonestOfferExpiry.toString();
|
||||||
|
|
||||||
|
now += unixTimesInMs.hour;
|
||||||
}
|
}
|
||||||
return cacheEntry;
|
return cacheEntry;
|
||||||
};
|
};
|
||||||
@ -388,4 +411,17 @@ if (isDev) {
|
|||||||
) {
|
) {
|
||||||
logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest`);
|
logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/GuildAdvertisementVendorManifest`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const pall = getVendorManifestByTypeName("/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest")!
|
||||||
|
.VendorInfo.ItemManifest;
|
||||||
|
if (
|
||||||
|
pall.length != 5 ||
|
||||||
|
pall[0].StoreItem != "/Lotus/StoreItems/Types/Items/ShipDecos/HarrowQuestKeyOrnament" ||
|
||||||
|
pall[1].StoreItem != "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack" ||
|
||||||
|
pall[2].StoreItem != "/Lotus/StoreItems/Types/StoreItems/CreditBundles/150000Credits" ||
|
||||||
|
pall[3].StoreItem != "/Lotus/StoreItems/Types/Items/MiscItems/Kuva" ||
|
||||||
|
pall[4].StoreItem != "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack"
|
||||||
|
) {
|
||||||
|
logger.warn(`self test failed for /Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest`);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,61 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "5f456e00c96976e97d6b7fd7"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Deimos/ProspectorVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Deimos/DeimosUncommonGemACutItem",
|
|
||||||
"PremiumPrice": [13, 13],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 10,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e93a8"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Deimos/DeimosCommonGemBCutItem",
|
|
||||||
"PremiumPrice": [7, 7],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e93a9"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Deimos/DeimosCommonGemACutItem",
|
|
||||||
"PremiumPrice": [7, 7],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e93aa"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "2BBC116116C757F6AF4FBC3B9BF754C8",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,125 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "5dbb4c41e966f7886c3ce939"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Hubs/IronwakeDondaVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/ShipDecos/HarrowQuestKeyOrnament",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 25,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/PrimeBucks",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e945f"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 10,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9468"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/StoreItems/CreditBundles/150000Credits",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 5,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9469"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/MiscItems/Kuva",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 10,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 35000,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e946a"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/BoosterPacks/RivenModPack",
|
|
||||||
"ItemPrices": [
|
|
||||||
{
|
|
||||||
"ItemCount": 10,
|
|
||||||
"ItemType": "/Lotus/Types/Items/MiscItems/RivenFragment",
|
|
||||||
"ProductCategory": "MiscItems"
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 1,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"PurchaseQuantityLimit": 1,
|
|
||||||
"AllowMultipurchase": false,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e946b"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "62B64A8065B7C0FA345895D4BC234621",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "604800000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,62 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "59dfe591314805ffe1d47c0a"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Ostron/ProspectorVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Eidolon/RareGemACutAItem",
|
|
||||||
"PremiumPrice": [19, 19],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 5,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e98f0"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Eidolon/CommonGemBCutAItem",
|
|
||||||
"PremiumPrice": [8, 8],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e98f1"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Eidolon/CommonGemACutAItem",
|
|
||||||
"PremiumPrice": [5, 5],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e98f2"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"MaxDailyPurchases": 0,
|
|
||||||
"PropertyTextHash": "773C6968D9A65506CD28DF28C768F0DA",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
@ -1,61 +0,0 @@
|
|||||||
{
|
|
||||||
"VendorInfo": {
|
|
||||||
"_id": {
|
|
||||||
"$oid": "5be4a159b144f3cdf1c22ebb"
|
|
||||||
},
|
|
||||||
"TypeName": "/Lotus/Types/Game/VendorManifests/Solaris/ProspectorVendorManifest",
|
|
||||||
"ItemManifest": [
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Solaris/SolarisRareGemACutItem",
|
|
||||||
"PremiumPrice": [20, 20],
|
|
||||||
"Bin": "BIN_1",
|
|
||||||
"QuantityMultiplier": 5,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9777"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Solaris/SolarisCommonGemBCutItem",
|
|
||||||
"PremiumPrice": [10, 10],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9778"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"StoreItem": "/Lotus/StoreItems/Types/Items/Gems/Solaris/SolarisCommonGemACutItem",
|
|
||||||
"PremiumPrice": [8, 8],
|
|
||||||
"Bin": "BIN_0",
|
|
||||||
"QuantityMultiplier": 20,
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
},
|
|
||||||
"AllowMultipurchase": true,
|
|
||||||
"Id": {
|
|
||||||
"$oid": "66fd60b20ba592c4c95e9779"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"PropertyTextHash": "A5756A21991FF49CFA7D096B4026515B",
|
|
||||||
"Expiry": {
|
|
||||||
"$date": {
|
|
||||||
"$numberLong": "9999999000000"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
Loading…
x
Reference in New Issue
Block a user