Compare commits

..

14 Commits

Author SHA1 Message Date
2c552f7b8a Fixed wrong quest key 2025-04-07 00:58:47 +02:00
e903dce307 Fix Second Dream rewards
Adds the two inbox mails that should be sent at the end of Second Dream.
2025-04-07 00:57:27 +02:00
5aedb579aa Merge branch 'main' of https://onlyg.it/VampireKitten/SpaceNinjaServerOnlyGit 2025-04-07 00:55:31 +02:00
5702ab5f3b fix: missing AutoContributeFromVault in guild response 2025-04-06 23:21:43 +02:00
fac52bfda1 fix: scale credits subtracted from clan vault when auto-contributing 2025-04-06 23:19:00 +02:00
2ff535e7ab chore: update PE+ 2025-04-06 21:20:00 +02:00
9698baa979 feat: handle droptable rewards from level key (#1492)
Reviewed-on: OpenWF/SpaceNinjaServer#1492
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-06 10:19:15 -07:00
ceb7deec06 chore: generate source maps with build (#1489)
This ensures that when we get a stack trace, it contains the original line numbers.

Reviewed-on: OpenWF/SpaceNinjaServer#1489
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-06 10:18:50 -07:00
fe0b745066 fix: missing fields in dojo response (#1488)
Reviewed-on: OpenWF/SpaceNinjaServer#1488
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-06 10:18:33 -07:00
8f41d3c13f fix: give an extra trade when leveling up MR (#1487)
Reviewed-on: OpenWF/SpaceNinjaServer#1487
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-06 10:18:15 -07:00
f906cdb5e8 fix: handle client providing an invalid loadout id at EOM upload (#1486)
Reviewed-on: OpenWF/SpaceNinjaServer#1486
Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com>
Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com>
2025-04-06 10:18:01 -07:00
ea6facf3fc chore(webui): update to German translation (#1490)
Reviewed-on: OpenWF/SpaceNinjaServer#1490
Co-authored-by: Animan8000 <animan8000@noreply.localhost>
Co-committed-by: Animan8000 <animan8000@noreply.localhost>
2025-04-06 06:44:11 -07:00
7a2c187d54 Fixed formatting 2025-02-25 18:50:37 +01:00
76e40685ab Fix acquiring blueprints as rewards
Fixes the acquisition of blueprints as rewards, such as those rewarded by the Junctions.
2025-02-25 17:59:23 +01:00
12 changed files with 111 additions and 72 deletions

8
package-lock.json generated
View File

@ -18,7 +18,7 @@
"morgan": "^1.10.0",
"ncp": "^2.0.0",
"typescript": ">=5.5 <5.6.0",
"warframe-public-export-plus": "^0.5.50",
"warframe-public-export-plus": "^0.5.52",
"warframe-riven-info": "^0.1.2",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0"
@ -3789,9 +3789,9 @@
}
},
"node_modules/warframe-public-export-plus": {
"version": "0.5.50",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.50.tgz",
"integrity": "sha512-KlhdY/Q5sRAIn/RhmdviKBoX3gk+Jtuen0cWnFB2zqK7eKYMDtd79bKOtTPtnK9zCNzh6gFug2wEeDVam3Bwlw=="
"version": "0.5.52",
"resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.52.tgz",
"integrity": "sha512-mJyQbTFMDwgBSkhUYJzcfJg9qrMTrL1pyZuAxV/Dov68xUikK5zigQSYM3ZkKYbhwBtg0Bx/+7q9GAmPzGaRhA=="
},
"node_modules/warframe-riven-info": {
"version": "0.1.2",

View File

@ -6,7 +6,7 @@
"scripts": {
"start": "node --import ./build/src/pathman.js build/src/index.js",
"dev": "ts-node-dev --openssl-legacy-provider -r tsconfig-paths/register src/index.ts ",
"build": "tsc --incremental && ncp static/webui build/static/webui",
"build": "tsc --incremental --sourceMap && ncp static/webui build/static/webui",
"verify": "tsgo --noEmit",
"lint": "eslint --ext .ts .",
"lint:fix": "eslint --fix --ext .ts .",
@ -24,7 +24,7 @@
"morgan": "^1.10.0",
"ncp": "^2.0.0",
"typescript": ">=5.5 <5.6.0",
"warframe-public-export-plus": "^0.5.50",
"warframe-public-export-plus": "^0.5.52",
"warframe-riven-info": "^0.1.2",
"winston": "^3.17.0",
"winston-daily-rotate-file": "^5.0.0"

View File

@ -77,8 +77,8 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) =
}
}
if (enoughMiscItems) {
guild.VaultRegularCredits -= meta.price;
deco.RegularCredits = meta.price;
guild.VaultRegularCredits -= scaleRequiredCount(guild.Tier, meta.price);
deco.RegularCredits = scaleRequiredCount(guild.Tier, meta.price);
deco.MiscItems = [];
for (const ingredient of meta.ingredients) {

View File

@ -23,7 +23,7 @@ const trainingResultController: RequestHandler = async (req, res): Promise<void>
const trainingResults = getJSONfromString<ITrainingResultsRequest>(String(req.body));
const inventory = await getInventory(accountId);
const inventory = await getInventory(accountId, "TrainingDate PlayerLevel TradesRemaining");
if (trainingResults.numLevelsGained == 1) {
let time = Date.now();
@ -33,6 +33,7 @@ const trainingResultController: RequestHandler = async (req, res): Promise<void>
inventory.TrainingDate = new Date(time);
inventory.PlayerLevel += 1;
inventory.TradesRemaining += 1;
await createMessage(accountId, [
{

View File

@ -95,7 +95,6 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
LongMOTD: guild.LongMOTD,
Members: members,
Ranks: guild.Ranks,
TradeTax: guild.TradeTax,
Tier: guild.Tier,
Vault: getGuildVault(guild),
ActiveDojoColorResearch: guild.ActiveDojoColorResearch,
@ -104,6 +103,7 @@ export const getGuildClient = async (guild: TGuildDatabaseDocument, accountId: s
IsContributor: !!guild.CeremonyContributors?.find(x => x.equals(accountId)),
NumContributors: guild.CeremonyContributors?.length ?? 0,
CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined,
AutoContributeFromVault: guild.AutoContributeFromVault,
AllianceId: guild.AllianceId ? toOid(guild.AllianceId) : undefined
};
};
@ -126,7 +126,11 @@ export const getDojoClient = async (
const dojo: IDojoClient = {
_id: { $oid: guild._id.toString() },
Name: guild.Name,
Tier: 1,
Tier: guild.Tier,
GuildEmblem: guild.Emblem,
TradeTax: guild.TradeTax,
NumContributors: guild.CeremonyContributors?.length ?? 0,
CeremonyResetDate: guild.CeremonyResetDate ? toMongoDate(guild.CeremonyResetDate) : undefined,
FixedContributions: true,
DojoRevision: 1,
Vault: getGuildVault(guild),

View File

@ -538,9 +538,15 @@ export const addItem = async (
if (!key) return {};
return { QuestKeys: [key] };
} else {
const levelKeyChanges = [{ ItemType: typeName, ItemCount: quantity }];
addLevelKeys(inventory, levelKeyChanges);
return { LevelKeys: levelKeyChanges };
const key = { ItemType: typeName, ItemCount: quantity };
const index = inventory.LevelKeys.findIndex(levelKey => levelKey.ItemType == typeName);
if (index != -1) {
inventory.LevelKeys[index].ItemCount += quantity;
} else {
inventory.LevelKeys.push(key);
}
return { LevelKeys: [key] };
}
}
if (typeName in ExportDrones) {
@ -1234,10 +1240,6 @@ export const addRecipes = (inventory: TInventoryDatabaseDocument, itemsArray: IT
applyArrayChanges(inventory.Recipes, itemsArray);
};
export const addLevelKeys = (inventory: TInventoryDatabaseDocument, itemsArray: ITypeCount[]): void => {
applyArrayChanges(inventory.LevelKeys, itemsArray);
};
export const addMods = (inventory: TInventoryDatabaseDocument, itemsArray: IRawUpgrade[]): void => {
const { RawUpgrades } = inventory;

View File

@ -22,7 +22,6 @@ import {
addFusionTreasures,
addGearExpByCategory,
addItem,
addLevelKeys,
addMiscItems,
addMissionComplete,
addMods,
@ -78,52 +77,19 @@ export const addMissionInventoryUpdates = async (
inventoryUpdates: IMissionInventoryUpdateRequest
): Promise<IInventoryChanges> => {
const inventoryChanges: IInventoryChanges = {};
if (inventoryUpdates.EndOfMatchUpload) {
if (inventoryUpdates.Missions && inventoryUpdates.Missions.Tag in ExportRegions) {
const node = ExportRegions[inventoryUpdates.Missions.Tag];
if (node.miscItemFee) {
addMiscItems(inventory, [
{
ItemType: node.miscItemFee.ItemType,
ItemCount: node.miscItemFee.ItemCount * -1
}
]);
}
}
if (inventoryUpdates.KeyToRemove) {
if (!inventoryUpdates.KeyOwner || inventory.accountOwnerId.equals(inventoryUpdates.KeyOwner)) {
addLevelKeys(inventory, [
{
ItemType: inventoryUpdates.KeyToRemove,
ItemCount: -1
}
]);
}
}
if (
inventoryUpdates.MissionFailed &&
inventoryUpdates.MissionStatus == "GS_FAILURE" &&
inventoryUpdates.ObjectiveReached &&
!inventoryUpdates.LockedWeaponGroup
) {
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
const config = loadout.NORMAL.id(inventory.CurrentLoadOutIds[0].$oid)!;
const SuitId = new Types.ObjectId(config.s!.ItemId.$oid);
inventory.BrandedSuits ??= [];
if (!inventory.BrandedSuits.find(x => x.equals(SuitId))) {
inventory.BrandedSuits.push(SuitId);
await createMessage(inventory.accountOwnerId, [
{
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
msg: "/Lotus/Language/G1Quests/BrandedMessage",
sub: "/Lotus/Language/G1Quests/BrandedTitle",
att: ["/Lotus/Types/Recipes/Components/BrandRemovalBlueprint"],
highPriority: true // TOVERIFY: I cannot find any content of this within the last 10 years so I can only assume that highPriority is set (it certainly would make sense), but I just don't know for sure that it is so on live.
}
]);
}
if (
inventoryUpdates.EndOfMatchUpload &&
inventoryUpdates.Missions &&
inventoryUpdates.Missions.Tag in ExportRegions
) {
const node = ExportRegions[inventoryUpdates.Missions.Tag];
if (node.miscItemFee) {
addMiscItems(inventory, [
{
ItemType: node.miscItemFee.ItemType,
ItemCount: node.miscItemFee.ItemCount * -1
}
]);
}
}
if (inventoryUpdates.RewardInfo) {
@ -144,6 +110,32 @@ export const addMissionInventoryUpdates = async (
inventory.NemesisAbandonedRewards = inventoryUpdates.RewardInfo.NemesisAbandonedRewards;
}
}
if (
inventoryUpdates.MissionFailed &&
inventoryUpdates.MissionStatus == "GS_FAILURE" &&
inventoryUpdates.EndOfMatchUpload &&
inventoryUpdates.ObjectiveReached &&
!inventoryUpdates.LockedWeaponGroup
) {
const loadout = (await Loadout.findById(inventory.LoadOutPresets, "NORMAL"))!;
const config = loadout.NORMAL.id(inventory.CurrentLoadOutIds[0].$oid)!;
const SuitId = new Types.ObjectId(config.s!.ItemId.$oid);
inventory.BrandedSuits ??= [];
if (!inventory.BrandedSuits.find(x => x.equals(SuitId))) {
inventory.BrandedSuits.push(SuitId);
await createMessage(inventory.accountOwnerId, [
{
sndr: "/Lotus/Language/Menu/Mailbox_WarframeSender",
msg: "/Lotus/Language/G1Quests/BrandedMessage",
sub: "/Lotus/Language/G1Quests/BrandedTitle",
att: ["/Lotus/Types/Recipes/Components/BrandRemovalBlueprint"],
highPriority: true // TOVERIFY: I cannot find any content of this within the last 10 years so I can only assume that highPriority is set (it certainly would make sense), but I just don't know for sure that it is so on live.
}
]);
}
}
for (const [key, value] of getEntriesUnsafe(inventoryUpdates)) {
if (value === undefined) {
logger.error(`Inventory update key ${key} has no value `);
@ -449,7 +441,12 @@ export const addMissionInventoryUpdates = async (
_id: new Types.ObjectId(ItemId.$oid),
...loadoutConfigItemIdRemoved
};
loadout.NORMAL.id(loadoutId)!.overwrite(loadoutConfigDatabase);
const dbConfig = loadout.NORMAL.id(loadoutId);
if (dbConfig) {
dbConfig.overwrite(loadoutConfigDatabase);
} else {
logger.warn(`couldn't update loadout because there's no config with id ${loadoutId}`);
}
}
await loadout.save();
}
@ -729,6 +726,20 @@ export const addFixedLevelRewards = (
MissionRewards.push(item);
}
}
if (rewards.droptable) {
if (rewards.droptable in ExportRewards) {
logger.debug(`rolling ${rewards.droptable} for level key rewards`);
const reward = getRandomRewardByChance(ExportRewards[rewards.droptable][0]);
if (reward) {
MissionRewards.push({
StoreItem: reward.type,
ItemCount: reward.itemCount
});
}
} else {
logger.error(`unknown droptable ${rewards.droptable}`);
}
}
return missionBonusCredits;
};

View File

@ -177,6 +177,22 @@ export const completeQuest = async (inventory: TInventoryDatabaseDocument, quest
await giveKeyChainMissionReward(inventory, { KeyChain: questKey, ChainStage: i });
}
if (questKey == "/Lotus/Types/Keys/OrokinMoonQuest/OrokinMoonQuestKeyChain") {
void createMessage(inventory.accountOwnerId, [
{
sndr: "/Lotus/Language/Bosses/Ordis",
msg: "/Lotus/Language/G1Quests/SecondDreamFinishInboxMessage",
att: [
"/Lotus/Weapons/Tenno/Melee/Swords/StalkerTwo/StalkerTwoSmallSword",
"/Lotus/Upgrades/Skins/Sigils/ScarSigil"
],
sub: "/Lotus/Language/G1Quests/SecondDreamFinishInboxTitle",
icon: "/Lotus/Interface/Icons/Npcs/Ordis.png",
highPriority: true
}
]);
}
const questCompletionItems = getQuestCompletionItems(questKey);
logger.debug(`quest completion items`, questCompletionItems);
if (questCompletionItems) {

View File

@ -10,7 +10,6 @@ export interface IGuildClient {
LongMOTD?: ILongMOTD;
Members: IGuildMemberClient[];
Ranks: IGuildRank[];
TradeTax: number;
Tier: number;
Vault: IGuildVault;
ActiveDojoColorResearch: string;
@ -143,6 +142,7 @@ export interface IDojoClient {
_id: IOid; // ID of the guild
Name: string;
Tier: number;
TradeTax?: number;
FixedContributions: boolean;
DojoRevision: number;
AllianceId?: IOid;
@ -155,6 +155,8 @@ export interface IDojoClient {
ContentURL?: string;
GuildEmblem?: boolean;
DojoComponents: IDojoComponentClient[];
NumContributors?: number;
CeremonyResetDate?: IMongoDate;
}
export interface IDojoComponentClient {

View File

@ -49,9 +49,6 @@ export type IMissionInventoryUpdateRequest = {
rewardsMultiplier?: number;
GoalTag: string;
LevelKeyName: string;
KeyOwner?: string;
KeyRemovalHash?: string;
KeyToRemove?: string;
ActiveBoosters?: IBooster[];
RawUpgrades?: IRawUpgrade[];
FusionTreasures?: IFusionTreasure[];

View File

@ -5,5 +5,11 @@
"ItemCount": 1
}
],
"/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain": [{ "ItemType": "/Lotus/Types/Recipes/WarframeRecipes/BrokenFrameBlueprint", "ItemCount": 1 }]
"/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain": [{ "ItemType": "/Lotus/Types/Recipes/WarframeRecipes/BrokenFrameBlueprint", "ItemCount": 1 }],
"/Lotus/Types/Keys/OrokinMoonQuest/OrokinMoonQuestKeyChain": [
{
"ItemType": "/Lotus/Types/Keys/RailJackBuildQuest/RailjackBuildQuestEmailItem",
"ItemCount": 1
}
]
}

View File

@ -132,7 +132,7 @@ dict = {
cheats_unlockArcanesEverywhere: `Arkana-Adapter überall`,
cheats_noDailyStandingLimits: `Kein tägliches Ansehenslimit`,
cheats_noArgonCrystalDecay: `Argon-Kristalle verschwinden niemals`,
cheats_noMasteryRankUpCooldown: `[UNTRANSLATED] No Mastery Rank Up Cooldown`,
cheats_noMasteryRankUpCooldown: `Keine Wartezeit beim Meisterschaftsrangaufstieg`,
cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`,
cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`,
cheats_noDojoRoomBuildStage: `Kein Dojo-Raum-Bauvorgang`,