Compare commits

..

4 Commits

Author SHA1 Message Date
d27934ab55 deduplicate static data by weighting it
Some checks failed
Build / build (pull_request) Failing after 48s
2025-06-27 01:24:49 +02:00
cbc4d1bdf9 Add noDarvoDealPurchaseLimit cheat
All checks were successful
Build / build (pull_request) Successful in 54s
2025-06-26 05:25:45 +02:00
b87ba3fef1 ensure stock is an int after multiplier 2025-06-26 05:25:45 +02:00
c038d51836 feat: daily deal 2025-06-26 05:25:45 +02:00
12 changed files with 43 additions and 74 deletions

View File

@ -34,5 +34,4 @@ SpaceNinjaServer requires a `config.json`. To set it up, you can copy the [confi
- `RadioLegion2Syndicate` for The Emissary - `RadioLegion2Syndicate` for The Emissary
- `RadioLegionIntermissionSyndicate` for Intermission I - `RadioLegionIntermissionSyndicate` for Intermission I
- `RadioLegionSyndicate` for The Wolf of Saturn Six - `RadioLegionSyndicate` for The Wolf of Saturn Six
- `allTheFissures` can be set to `normal` or `hard` to enable all fissures either in normal or steel path, respectively.
- `worldState.circuitGameModes` can be provided with an array of valid game modes (`Survival`, `VoidFlood`, `Excavation`, `Defense`, `Exterminate`, `Assassination`, `Alchemy`) - `worldState.circuitGameModes` can be provided with an array of valid game modes (`Survival`, `VoidFlood`, `Excavation`, `Defense`, `Exterminate`, `Assassination`, `Alchemy`)

View File

@ -75,7 +75,6 @@
"vallisOverride": "", "vallisOverride": "",
"duviriOverride": "", "duviriOverride": "",
"nightwaveOverride": "", "nightwaveOverride": "",
"allTheFissures": "",
"circuitGameModes": null, "circuitGameModes": null,
"darvoStockMultiplier": 1 "darvoStockMultiplier": 1
}, },

12
package-lock.json generated
View File

@ -14,7 +14,6 @@
"@types/websocket": "^1.0.10", "@types/websocket": "^1.0.10",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"@typescript/native-preview": "^7.0.0-dev.20250625.1", "@typescript/native-preview": "^7.0.0-dev.20250625.1",
"chokidar": "^4.0.3",
"crc-32": "^1.2.2", "crc-32": "^1.2.2",
"express": "^5", "express": "^5",
"json-with-bigint": "^3.4.4", "json-with-bigint": "^3.4.4",
@ -23,7 +22,7 @@
"ncp": "^2.0.0", "ncp": "^2.0.0",
"typescript": "^5.5", "typescript": "^5.5",
"undici": "^7.10.0", "undici": "^7.10.0",
"warframe-public-export-plus": "^0.5.72", "warframe-public-export-plus": "^0.5.71",
"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",
@ -32,6 +31,7 @@
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.28.0", "@typescript-eslint/eslint-plugin": "^8.28.0",
"@typescript-eslint/parser": "^8.28.0", "@typescript-eslint/parser": "^8.28.0",
"chokidar": "^4.0.3",
"eslint": "^8", "eslint": "^8",
"eslint-plugin-prettier": "^5.2.5", "eslint-plugin-prettier": "^5.2.5",
"prettier": "^3.5.3", "prettier": "^3.5.3",
@ -997,6 +997,7 @@
"version": "4.0.3", "version": "4.0.3",
"resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz", "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-4.0.3.tgz",
"integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==", "integrity": "sha512-Qgzu8kfBvo+cA4962jnP1KkS6Dop5NS6g7R5LFYJr4b8Ub94PPQXUksCw9PvXoeXPRRddRNC5C1JQUR2SMGtnA==",
"dev": true,
"license": "MIT", "license": "MIT",
"dependencies": { "dependencies": {
"readdirp": "^4.0.1" "readdirp": "^4.0.1"
@ -2802,6 +2803,7 @@
"version": "4.1.2", "version": "4.1.2",
"resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz", "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-4.1.2.tgz",
"integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==", "integrity": "sha512-GDhwkLfywWL2s6vEjyhri+eXmfH6j1L7JE27WhqLeYzoh/A3DBaYGEj2H/HFZCn/kMfim73FXxEJTw06WtxQwg==",
"dev": true,
"license": "MIT", "license": "MIT",
"engines": { "engines": {
"node": ">= 14.18.0" "node": ">= 14.18.0"
@ -3386,9 +3388,9 @@
} }
}, },
"node_modules/warframe-public-export-plus": { "node_modules/warframe-public-export-plus": {
"version": "0.5.72", "version": "0.5.71",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.72.tgz", "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.71.tgz",
"integrity": "sha512-oOZgtU6L0MGcPRKfA6+bonu+Db1kie1lVdLmA7/DbheTPweNkBEx3Hx3Seib+hEaFW+nLj3T5GtmGxGcFHCHfg==" "integrity": "sha512-TCS2wPRsBzuURJlIMDhygAHaLsKVZ7dGuC73WZ/iMyn3gKVwA98nnaIj24D+UceWS08fwq4ilWAfUzHJd6X29A=="
}, },
"node_modules/warframe-riven-info": { "node_modules/warframe-riven-info": {
"version": "0.1.2", "version": "0.1.2",

View File

@ -28,7 +28,6 @@
"@types/websocket": "^1.0.10", "@types/websocket": "^1.0.10",
"@types/ws": "^8.18.1", "@types/ws": "^8.18.1",
"@typescript/native-preview": "^7.0.0-dev.20250625.1", "@typescript/native-preview": "^7.0.0-dev.20250625.1",
"chokidar": "^4.0.3",
"crc-32": "^1.2.2", "crc-32": "^1.2.2",
"express": "^5", "express": "^5",
"json-with-bigint": "^3.4.4", "json-with-bigint": "^3.4.4",
@ -37,7 +36,7 @@
"ncp": "^2.0.0", "ncp": "^2.0.0",
"typescript": "^5.5", "typescript": "^5.5",
"undici": "^7.10.0", "undici": "^7.10.0",
"warframe-public-export-plus": "^0.5.72", "warframe-public-export-plus": "^0.5.71",
"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",
@ -46,6 +45,7 @@
"devDependencies": { "devDependencies": {
"@typescript-eslint/eslint-plugin": "^8.28.0", "@typescript-eslint/eslint-plugin": "^8.28.0",
"@typescript-eslint/parser": "^8.28.0", "@typescript-eslint/parser": "^8.28.0",
"chokidar": "^4.0.3",
"eslint": "^8", "eslint": "^8",
"eslint-plugin-prettier": "^5.2.5", "eslint-plugin-prettier": "^5.2.5",
"prettier": "^3.5.3", "prettier": "^3.5.3",

View File

@ -82,7 +82,6 @@ export interface IConfig {
vallisOverride?: string; vallisOverride?: string;
duviriOverride?: string; duviriOverride?: string;
nightwaveOverride?: string; nightwaveOverride?: string;
allTheFissures?: string;
circuitGameModes?: string[]; circuitGameModes?: string[];
darvoStockMultiplier?: number; darvoStockMultiplier?: number;
}; };

View File

@ -1,4 +1,4 @@
import chokidar from "chokidar"; import fs from "fs";
import fsPromises from "fs/promises"; import fsPromises from "fs/promises";
import { logger } from "../utils/logger"; import { logger } from "../utils/logger";
import { config, configPath, loadConfig } from "./configService"; import { config, configPath, loadConfig } from "./configService";
@ -6,7 +6,12 @@ import { getWebPorts, sendWsBroadcast, startWebServer, stopWebServer } from "./w
import { Inbox } from "../models/inboxModel"; import { Inbox } from "../models/inboxModel";
let amnesia = false; let amnesia = false;
chokidar.watch(configPath).on("change", () => { fs.watchFile(configPath, (now, then) => {
// https://github.com/oven-sh/bun/issues/20542
if (process.versions.bun && now.mtimeMs == then.mtimeMs) {
return;
}
if (amnesia) { if (amnesia) {
amnesia = false; amnesia = false;
} else { } else {

View File

@ -499,7 +499,6 @@ export const addItem = async (
// - Blueprints for Ancient Protector Specter, Shield Osprey Specter, etc. have num=1 despite giving their purchaseQuantity. // - Blueprints for Ancient Protector Specter, Shield Osprey Specter, etc. have num=1 despite giving their purchaseQuantity.
if (!exactQuantity) { if (!exactQuantity) {
quantity *= ExportGear[typeName].purchaseQuantity ?? 1; quantity *= ExportGear[typeName].purchaseQuantity ?? 1;
logger.debug(`non-exact acquisition of ${typeName}; factored quantity is ${quantity}`);
} }
const consumablesChanges = [ const consumablesChanges = [
{ {

View File

@ -398,28 +398,18 @@ export const handleStoreItemAcquisition = async (
} else { } else {
const storeCategory = getStoreItemCategory(storeItemName); const storeCategory = getStoreItemCategory(storeItemName);
const internalName = fromStoreItem(storeItemName); const internalName = fromStoreItem(storeItemName);
logger.debug(`store category ${storeCategory}`);
if (!ignorePurchaseQuantity) { if (!ignorePurchaseQuantity) {
if (internalName in ExportGear) { if (internalName in ExportGear) {
quantity *= ExportGear[internalName].purchaseQuantity || 1; quantity *= ExportGear[internalName].purchaseQuantity || 1;
logger.debug(`factored quantity is ${quantity}`);
} else if (internalName in ExportResources) { } else if (internalName in ExportResources) {
quantity *= ExportResources[internalName].purchaseQuantity || 1; quantity *= ExportResources[internalName].purchaseQuantity || 1;
logger.debug(`factored quantity is ${quantity}`);
} }
} }
logger.debug(`store category ${storeCategory}`);
switch (storeCategory) { switch (storeCategory) {
default: { default: {
purchaseResponse = { purchaseResponse = {
InventoryChanges: await addItem( InventoryChanges: await addItem(inventory, internalName, quantity, premiumPurchase, seed)
inventory,
internalName,
quantity,
premiumPurchase,
seed,
undefined,
true
)
}; };
break; break;
} }
@ -561,9 +551,7 @@ const handleTypesPurchase = async (
logger.debug(`type category ${typeCategory}`); logger.debug(`type category ${typeCategory}`);
switch (typeCategory) { switch (typeCategory) {
default: default:
return { return { InventoryChanges: await addItem(inventory, typesName, quantity, premiumPurchase, seed) };
InventoryChanges: await addItem(inventory, typesName, quantity, premiumPurchase, seed, undefined, true)
};
case "BoosterPacks": case "BoosterPacks":
return handleBoosterPackPurchase(typesName, inventory, quantity); return handleBoosterPackPurchase(typesName, inventory, quantity);
case "SlotItems": case "SlotItems":

View File

@ -1526,40 +1526,20 @@ export const getWorldState = (buildLabel?: string): IWorldState => {
}; };
export const populateFissures = async (worldState: IWorldState): Promise<void> => { export const populateFissures = async (worldState: IWorldState): Promise<void> => {
if (config.worldState?.allTheFissures) { const fissures = await Fissure.find({});
let i = 0; for (const fissure of fissures) {
for (const [tier, nodes] of Object.entries(fissureMissions)) { const meta = ExportRegions[fissure.Node];
for (const node of nodes) { worldState.ActiveMissions.push({
const meta = ExportRegions[node]; _id: toOid(fissure._id),
worldState.ActiveMissions.push({ Region: meta.systemIndex + 1,
_id: { $oid: (i++).toString().padStart(8, "0") + "8e0c70ba050f1eb7" }, Seed: 1337,
Region: meta.systemIndex + 1, Activation: toMongoDate(fissure.Activation),
Seed: 1337, Expiry: toMongoDate(fissure.Expiry),
Activation: { $date: { $numberLong: "1000000000000" } }, Node: fissure.Node,
Expiry: { $date: { $numberLong: "2000000000000" } }, MissionType: eMissionType[meta.missionIndex].tag,
Node: node, Modifier: fissure.Modifier,
MissionType: eMissionType[meta.missionIndex].tag, Hard: fissure.Hard
Modifier: tier, });
Hard: config.worldState.allTheFissures == "hard"
});
}
}
} else {
const fissures = await Fissure.find({});
for (const fissure of fissures) {
const meta = ExportRegions[fissure.Node];
worldState.ActiveMissions.push({
_id: toOid(fissure._id),
Region: meta.systemIndex + 1,
Seed: 1337,
Activation: toMongoDate(fissure.Activation),
Expiry: toMongoDate(fissure.Expiry),
Node: fissure.Node,
MissionType: eMissionType[meta.missionIndex].tag,
Modifier: fissure.Modifier,
Hard: fissure.Hard
});
}
} }
}; };

View File

@ -45,6 +45,5 @@
"/Lotus/Weapons/Tenno/Zariman/Melee/Tonfas/ZarimanTonfaWeapon", "/Lotus/Weapons/Tenno/Zariman/Melee/Tonfas/ZarimanTonfaWeapon",
"/Lotus/Weapons/Tenno/Zariman/Pistols/HeavyPistol/ZarimanHeavyPistol", "/Lotus/Weapons/Tenno/Zariman/Pistols/HeavyPistol/ZarimanHeavyPistol",
"/Lotus/Weapons/Thanotech/EntFistIncarnon/EntFistIncarnon", "/Lotus/Weapons/Thanotech/EntFistIncarnon/EntFistIncarnon",
"/Lotus/Weapons/Thanotech/EntratiWristGun/EntratiWristGunWeapon", "/Lotus/Weapons/Thanotech/EntratiWristGun/EntratiWristGunWeapon"
"/Lotus/Weapons/Tenno/Zariman/Melee/HeavyScythe/ZarimanHeavyScythe/ZarimanHeavyScytheWeapon"
] ]

View File

@ -248,8 +248,7 @@ const permanentEvolutionWeapons = new Set([
"/Lotus/Weapons/Tenno/Zariman/Melee/Tonfas/ZarimanTonfaWeapon", "/Lotus/Weapons/Tenno/Zariman/Melee/Tonfas/ZarimanTonfaWeapon",
"/Lotus/Weapons/Tenno/Zariman/Pistols/HeavyPistol/ZarimanHeavyPistol", "/Lotus/Weapons/Tenno/Zariman/Pistols/HeavyPistol/ZarimanHeavyPistol",
"/Lotus/Weapons/Thanotech/EntFistIncarnon/EntFistIncarnon", "/Lotus/Weapons/Thanotech/EntFistIncarnon/EntFistIncarnon",
"/Lotus/Weapons/Thanotech/EntratiWristGun/EntratiWristGunWeapon", "/Lotus/Weapons/Thanotech/EntratiWristGun/EntratiWristGunWeapon"
"/Lotus/Weapons/Tenno/Zariman/Melee/HeavyScythe/ZarimanHeavyScythe/ZarimanHeavyScytheWeapon"
]); ]);
let uniqueLevelCaps = {}; let uniqueLevelCaps = {};

View File

@ -74,9 +74,9 @@ dict = {
inventory_longGuns: `主要武器`, inventory_longGuns: `主要武器`,
inventory_pistols: `次要武器`, inventory_pistols: `次要武器`,
inventory_melee: `近战武器`, inventory_melee: `近战武器`,
inventory_spaceSuits: `载具`, inventory_spaceSuits: `Archwings`,
inventory_spaceGuns: `载具主武器`, inventory_spaceGuns: `Archwing主武器`,
inventory_spaceMelee: `载具近战武器`, inventory_spaceMelee: `Archwing近战武器`,
inventory_mechSuits: `殁世机甲`, inventory_mechSuits: `殁世机甲`,
inventory_sentinels: `守护`, inventory_sentinels: `守护`,
inventory_sentinelWeapons: `守护武器`, inventory_sentinelWeapons: `守护武器`,
@ -88,15 +88,15 @@ dict = {
inventory_Boosters: `加成器`, inventory_Boosters: `加成器`,
inventory_bulkAddSuits: `添加缺失战甲`, inventory_bulkAddSuits: `添加缺失战甲`,
inventory_bulkAddWeapons: `添加缺失武器`, inventory_bulkAddWeapons: `添加缺失武器`,
inventory_bulkAddSpaceSuits: `添加缺失载具`, inventory_bulkAddSpaceSuits: `添加缺失Archwing`,
inventory_bulkAddSpaceWeapons: `添加缺失载具武器`, inventory_bulkAddSpaceWeapons: `添加缺失Archwing武器`,
inventory_bulkAddSentinels: `添加缺失守护`, inventory_bulkAddSentinels: `添加缺失守护`,
inventory_bulkAddSentinelWeapons: `添加缺失守护武器`, inventory_bulkAddSentinelWeapons: `添加缺失守护武器`,
inventory_bulkAddEvolutionProgress: `添加缺失的灵化之源`, inventory_bulkAddEvolutionProgress: `添加缺失的灵化之源`,
inventory_bulkRankUpSuits: `所有战甲升满级`, inventory_bulkRankUpSuits: `所有战甲升满级`,
inventory_bulkRankUpWeapons: `所有武器升满级`, inventory_bulkRankUpWeapons: `所有武器升满级`,
inventory_bulkRankUpSpaceSuits: `所有载具升满级`, inventory_bulkRankUpSpaceSuits: `所有Archwing升满级`,
inventory_bulkRankUpSpaceWeapons: `所有载具武器升满级`, inventory_bulkRankUpSpaceWeapons: `所有Archwing武器升满级`,
inventory_bulkRankUpSentinels: `所有守护升满级`, inventory_bulkRankUpSentinels: `所有守护升满级`,
inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`, inventory_bulkRankUpSentinelWeapons: `所有守护武器升满级`,
inventory_bulkRankUpEvolutionProgress: `所有灵化之源最大等级`, inventory_bulkRankUpEvolutionProgress: `所有灵化之源最大等级`,
@ -182,7 +182,7 @@ dict = {
cheats_account: `账户`, cheats_account: `账户`,
cheats_unlockAllFocusSchools: `解锁所有专精学派`, cheats_unlockAllFocusSchools: `解锁所有专精学派`,
cheats_helminthUnlockAll: `完全升级Helminth`, cheats_helminthUnlockAll: `完全升级Helminth`,
cheats_addMissingSubsumedAbilities: `添加Helminth未汲取的战甲技能`, cheats_addMissingSubsumedAbilities: `[UNTRANSLATED] Add Missing Subsumed Abilities`,
cheats_intrinsicsUnlockAll: `所有内源之力最大等级`, cheats_intrinsicsUnlockAll: `所有内源之力最大等级`,
cheats_changeSupportedSyndicate: `支持的集团`, cheats_changeSupportedSyndicate: `支持的集团`,
cheats_changeButton: `更改`, cheats_changeButton: `更改`,