From 5a5f6106a34425cea7efb8fa739d0a2775c5864f Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Mon, 30 Jun 2025 17:55:06 -0700 Subject: [PATCH 1/7] chore: save inventory and account in parallel when claiming login reward (#2371) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2371 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/api/loginRewardsController.ts | 4 +--- src/controllers/api/loginRewardsSelectionController.ts | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/src/controllers/api/loginRewardsController.ts b/src/controllers/api/loginRewardsController.ts index 19940d08..7678722f 100644 --- a/src/controllers/api/loginRewardsController.ts +++ b/src/controllers/api/loginRewardsController.ts @@ -48,10 +48,8 @@ export const loginRewardsController: RequestHandler = async (req, res) => { response.DailyTributeInfo.HasChosenReward = true; response.DailyTributeInfo.ChosenReward = randomRewards[0]; response.DailyTributeInfo.NewInventory = await claimLoginReward(inventory, randomRewards[0]); - await inventory.save(); - setAccountGotLoginRewardToday(account); - await account.save(); + await Promise.all([inventory.save(), account.save()]); sendWsBroadcastTo(account._id.toString(), { update_inventory: true }); } diff --git a/src/controllers/api/loginRewardsSelectionController.ts b/src/controllers/api/loginRewardsSelectionController.ts index e3a699ec..63e160f6 100644 --- a/src/controllers/api/loginRewardsSelectionController.ts +++ b/src/controllers/api/loginRewardsSelectionController.ts @@ -35,10 +35,8 @@ export const loginRewardsSelectionController: RequestHandler = async (req, res) chosenReward = randomRewards.find(x => x.StoreItemType == body.ChosenReward)!; inventoryChanges = await claimLoginReward(inventory, chosenReward); } - await inventory.save(); - setAccountGotLoginRewardToday(account); - await account.save(); + await Promise.all([inventory.save(), account.save()]); sendWsBroadcastTo(account._id.toString(), { update_inventory: true }); res.json({ From aa916d28208e7eb22514203f602ecf6e61f5b2df Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:44:05 -0700 Subject: [PATCH 2/7] feat: sell genetic imprints (#2368) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2368 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/api/sellController.ts | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/src/controllers/api/sellController.ts b/src/controllers/api/sellController.ts index ccc96385..7e2926ae 100644 --- a/src/controllers/api/sellController.ts +++ b/src/controllers/api/sellController.ts @@ -19,6 +19,7 @@ import { sendWsBroadcastTo } from "@/src/services/webService"; export const sellController: RequestHandler = async (req, res) => { const payload = JSON.parse(String(req.body)) as ISellRequest; + //console.log(JSON.stringify(payload, null, 2)); const accountId = await getAccountIdForRequest(req); const requiredFields = new Set(); if (payload.SellCurrency == "SC_RegularCredits") { @@ -184,6 +185,11 @@ export const sellController: RequestHandler = async (req, res) => { inventory.Drones.pull({ _id: sellItem.String }); }); } + if (payload.Items.KubrowPetPrints) { + payload.Items.KubrowPetPrints.forEach(sellItem => { + inventory.KubrowPetPrints.pull({ _id: sellItem.String }); + }); + } if (payload.Items.CrewMembers) { payload.Items.CrewMembers.forEach(sellItem => { inventory.CrewMembers.pull({ _id: sellItem.String }); @@ -312,6 +318,7 @@ interface ISellRequest { OperatorAmps?: ISellItem[]; Hoverboards?: ISellItem[]; Drones?: ISellItem[]; + KubrowPetPrints?: ISellItem[]; CrewMembers?: ISellItem[]; CrewShipWeapons?: ISellItem[]; CrewShipWeaponSkins?: ISellItem[]; From 75832afdbe3f1d9908dd398278682d910952570a Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:44:13 -0700 Subject: [PATCH 3/7] feat: relicRewardItemCountMultiplier cheat (#2369) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2369 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- config.json.example | 1 + src/helpers/relicHelper.ts | 9 ++++++++- src/services/configService.ts | 1 + static/webui/index.html | 13 ++++++++++--- static/webui/script.js | 18 ++++++++---------- static/webui/translations/de.js | 1 + static/webui/translations/en.js | 1 + static/webui/translations/es.js | 1 + static/webui/translations/fr.js | 1 + static/webui/translations/ru.js | 1 + static/webui/translations/zh.js | 1 + 11 files changed, 34 insertions(+), 14 deletions(-) diff --git a/config.json.example b/config.json.example index 70044e43..bb0c1cf2 100644 --- a/config.json.example +++ b/config.json.example @@ -60,6 +60,7 @@ "unlockAllSimarisResearchEntries": false, "disableDailyTribute": false, "spoofMasteryRank": -1, + "relicRewardItemCountMultiplier": 1, "nightwaveStandingMultiplier": 1, "unfaithfulBugFixes": { "ignore1999LastRegionPlayed": false, diff --git a/src/helpers/relicHelper.ts b/src/helpers/relicHelper.ts index 13d7d7d4..03b0e9c9 100644 --- a/src/helpers/relicHelper.ts +++ b/src/helpers/relicHelper.ts @@ -6,6 +6,7 @@ import { logger } from "@/src/utils/logger"; import { addMiscItems, combineInventoryChanges } from "@/src/services/inventoryService"; import { handleStoreItemAcquisition } from "@/src/services/purchaseService"; import { IInventoryChanges } from "../types/purchaseTypes"; +import { config } from "../services/configService"; export const crackRelic = async ( inventory: TInventoryDatabaseDocument, @@ -35,7 +36,13 @@ export const crackRelic = async ( // Give reward combineInventoryChanges( inventoryChanges, - (await handleStoreItemAcquisition(reward.type, inventory, reward.itemCount)).InventoryChanges + ( + await handleStoreItemAcquisition( + reward.type, + inventory, + reward.itemCount * (config.relicRewardItemCountMultiplier ?? 1) + ) + ).InventoryChanges ); return reward; diff --git a/src/services/configService.ts b/src/services/configService.ts index e96ace26..aa649dd5 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -67,6 +67,7 @@ export interface IConfig { unlockAllSimarisResearchEntries?: boolean; disableDailyTribute?: boolean; spoofMasteryRank?: number; + relicRewardItemCountMultiplier?: number; nightwaveStandingMultiplier?: number; unfaithfulBugFixes?: { ignore1999LastRegionPlayed?: boolean; diff --git a/static/webui/index.html b/static/webui/index.html index c228a9ef..2f81fb39 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -788,14 +788,21 @@
- + + +
+
+
+ +
+
- +
@@ -919,7 +926,7 @@
- +
diff --git a/static/webui/script.js b/static/webui/script.js index f648809c..34b39060 100644 --- a/static/webui/script.js +++ b/static/webui/script.js @@ -1984,16 +1984,14 @@ single.getRoute("/webui/cheats").on("beforeload", function () { $(".config-admin-show").removeClass("d-none"); Object.entries(json).forEach(entry => { const [key, value] = entry; - var x = document.getElementById(`${key}`); - if (x != null) { - if (x.type == "checkbox") { - x.checked = value; - } else if (x.classList.contains("tags-input")) { - x.value = value.join(", "); - x.oninput(); - } else { - x.value = value; - } + const elm = document.getElementById(key); + if (elm.type == "checkbox") { + elm.checked = value; + } else if (elm.classList.contains("tags-input")) { + elm.value = value.join(", "); + elm.oninput(); + } else { + elm.value = value ?? elm.getAttribute("data-default"); } }); }) diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index e6b12f57..73d78a66 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -185,6 +185,7 @@ dict = { cheats_unlockAllSimarisResearchEntries: `[UNTRANSLATED] Unlock All Simaris Research Entries`, cheats_disableDailyTribute: `[UNTRANSLATED] Disable Daily Tribute`, cheats_spoofMasteryRank: `Gefälschter Meisterschaftsrang (-1 zum deaktivieren)`, + cheats_relicRewardItemCountMultiplier: `[UNTRANSLATED] Relic Reward Item Count Multiplier`, cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`, cheats_save: `[UNTRANSLATED] Save`, cheats_account: `Account`, diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index c18e34d3..65594d49 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -184,6 +184,7 @@ dict = { cheats_unlockAllSimarisResearchEntries: `Unlock All Simaris Research Entries`, cheats_disableDailyTribute: `Disable Daily Tribute`, cheats_spoofMasteryRank: `Spoofed Mastery Rank (-1 to disable)`, + cheats_relicRewardItemCountMultiplier: `Relic Reward Item Count Multiplier`, cheats_nightwaveStandingMultiplier: `Nightwave Standing Multiplier`, cheats_save: `Save`, cheats_account: `Account`, diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js index 86d8c6be..7b480e61 100644 --- a/static/webui/translations/es.js +++ b/static/webui/translations/es.js @@ -185,6 +185,7 @@ dict = { cheats_unlockAllSimarisResearchEntries: `Desbloquear todas las entradas de investigación de Simaris`, cheats_disableDailyTribute: `Desactivar tributo diario`, cheats_spoofMasteryRank: `Rango de maestría simulado (-1 para desactivar)`, + cheats_relicRewardItemCountMultiplier: `[UNTRANSLATED] Relic Reward Item Count Multiplier`, cheats_nightwaveStandingMultiplier: `Multiplicador de Reputación de Onda Nocturna`, cheats_save: `Guardar`, cheats_account: `Cuenta`, diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index e35bc9ac..ef70cd6e 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -185,6 +185,7 @@ dict = { cheats_unlockAllSimarisResearchEntries: `Débloquer toute les recherches chez Simaris`, cheats_disableDailyTribute: `[UNTRANSLATED] Disable Daily Tribute`, cheats_spoofMasteryRank: `Rang de maîtrise personnalisé (-1 pour désactiver)`, + cheats_relicRewardItemCountMultiplier: `[UNTRANSLATED] Relic Reward Item Count Multiplier`, cheats_nightwaveStandingMultiplier: `Multiplicateur de réputation d'Ondes Nocturnes`, cheats_save: `Sauvegarder`, cheats_account: `Compte`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index 0666c75c..7f594867 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -185,6 +185,7 @@ dict = { cheats_unlockAllSimarisResearchEntries: `[UNTRANSLATED] Unlock All Simaris Research Entries`, cheats_disableDailyTribute: `[UNTRANSLATED] Disable Daily Tribute`, cheats_spoofMasteryRank: `Подделанный ранг мастерства (-1 для отключения)`, + cheats_relicRewardItemCountMultiplier: `[UNTRANSLATED] Relic Reward Item Count Multiplier`, cheats_nightwaveStandingMultiplier: `[UNTRANSLATED] Nightwave Standing Multiplier`, cheats_save: `[UNTRANSLATED] Save`, cheats_account: `Аккаунт`, diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index a15bc3a8..d62614ca 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -185,6 +185,7 @@ dict = { cheats_unlockAllSimarisResearchEntries: `解锁所有Simaris研究条目`, cheats_disableDailyTribute: `禁用每日登录奖励`, cheats_spoofMasteryRank: `伪造精通段位(-1为禁用)`, + cheats_relicRewardItemCountMultiplier: `[UNTRANSLATED] Relic Reward Item Count Multiplier`, cheats_nightwaveStandingMultiplier: `午夜电波声望倍率`, cheats_save: `保存`, cheats_account: `账户`, From fd1d72a1cfec984e7f78240a8846558d8060a8c9 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:44:30 -0700 Subject: [PATCH 4/7] chore(webui): add inventory update note to quests tab (#2372) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2372 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- static/webui/index.html | 1 + 1 file changed, 1 insertion(+) diff --git a/static/webui/index.html b/static/webui/index.html index 2f81fb39..80493572 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -546,6 +546,7 @@
+

From a9b3b16d31628a54da35b8871daf52990c17fc8e Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:45:12 -0700 Subject: [PATCH 5/7] feat: dojo visitors (#2374) Closes #2373 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2374 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- package-lock.json | 8 ++++---- package.json | 2 +- src/controllers/api/guildTechController.ts | 9 +++++++-- .../api/placeDecoInComponentController.ts | 16 +++++++++++++--- src/services/guildService.ts | 13 +++++++++++++ src/services/shipCustomizationsService.ts | 8 ++++++-- static/fixed_responses/allDecoRecipes.json | 10 +++++++++- 7 files changed, 53 insertions(+), 13 deletions(-) diff --git a/package-lock.json b/package-lock.json index db97566d..7fbb4684 100644 --- a/package-lock.json +++ b/package-lock.json @@ -23,7 +23,7 @@ "ncp": "^2.0.0", "typescript": "^5.5", "undici": "^7.10.0", - "warframe-public-export-plus": "^0.5.74", + "warframe-public-export-plus": "^0.5.76", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0", @@ -3386,9 +3386,9 @@ } }, "node_modules/warframe-public-export-plus": { - "version": "0.5.74", - "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.74.tgz", - "integrity": "sha512-pA7dxA0lKn9w/2Sc97oxnn+CEzL1SrT9XriNLTDF4Xp+2SBEpGcfbqbdR9ljPQJopIbrc9Zy02R+uBQVomcwyA==" + "version": "0.5.76", + "resolved": "https://registry.npmjs.org/warframe-public-export-plus/-/warframe-public-export-plus-0.5.76.tgz", + "integrity": "sha512-0gX3NTWaxFyzUmqBSUHhPY8pMRX92iXQFqoBuMQlMG1+6uC6JMKtwP5t8cuXR3pvV2vkaCi/cDWjP1JUChkZ9g==" }, "node_modules/warframe-riven-info": { "version": "0.1.2", diff --git a/package.json b/package.json index 99f8c63d..eed277ae 100644 --- a/package.json +++ b/package.json @@ -37,7 +37,7 @@ "ncp": "^2.0.0", "typescript": "^5.5", "undici": "^7.10.0", - "warframe-public-export-plus": "^0.5.74", + "warframe-public-export-plus": "^0.5.76", "warframe-riven-info": "^0.1.2", "winston": "^3.17.0", "winston-daily-rotate-file": "^5.0.0", diff --git a/src/controllers/api/guildTechController.ts b/src/controllers/api/guildTechController.ts index 97abbecf..f3e37217 100644 --- a/src/controllers/api/guildTechController.ts +++ b/src/controllers/api/guildTechController.ts @@ -5,6 +5,7 @@ import { getGuildVault, hasAccessToDojo, hasGuildPermission, + processCompletedGuildTechProject, processFundedGuildTechProject, processGuildTechProjectContributionsUpdate, removePigmentsFromGuildMembers, @@ -51,8 +52,12 @@ export const guildTechController: RequestHandler = async (req, res) => { }; if (project.CompletionDate) { techProject.CompletionDate = toMongoDate(project.CompletionDate); - if (Date.now() >= project.CompletionDate.getTime()) { - needSave ||= setGuildTechLogState(guild, project.ItemType, 4, project.CompletionDate); + if ( + Date.now() >= project.CompletionDate.getTime() && + setGuildTechLogState(guild, project.ItemType, 4, project.CompletionDate) + ) { + processCompletedGuildTechProject(guild, project.ItemType); + needSave = true; } } techProjects.push(techProject); diff --git a/src/controllers/api/placeDecoInComponentController.ts b/src/controllers/api/placeDecoInComponentController.ts index 088f1f11..fc1ef445 100644 --- a/src/controllers/api/placeDecoInComponentController.ts +++ b/src/controllers/api/placeDecoInComponentController.ts @@ -57,8 +57,12 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) = component.DecoCapacity -= meta.capacityCost; } } else { - const [itemType, meta] = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type)!; - if (!itemType || meta.dojoCapacityCost === undefined) { + const entry = Object.entries(ExportResources).find(arr => arr[1].deco == deco.Type); + if (!entry) { + throw new Error(`unknown deco type: ${deco.Type}`); + } + const [itemType, meta] = entry; + if (meta.dojoCapacityCost === undefined) { throw new Error(`unknown deco type: ${deco.Type}`); } component.DecoCapacity -= meta.dojoCapacityCost; @@ -75,7 +79,13 @@ export const placeDecoInComponentController: RequestHandler = async (req, res) = if (meta) { processDojoBuildMaterialsGathered(guild, meta); } - } else if (guild.AutoContributeFromVault && guild.VaultRegularCredits && guild.VaultMiscItems) { + } else if ( + deco.Type.startsWith("/Lotus/Objects/Tenno/Dojo/NpcPlaceables/") || + (guild.AutoContributeFromVault && guild.VaultRegularCredits && guild.VaultMiscItems) + ) { + if (!guild.VaultRegularCredits || !guild.VaultMiscItems) { + throw new Error(`dojo visitor placed without anything in vault?!`); + } if (guild.VaultRegularCredits >= scaleRequiredCount(guild.Tier, meta.price)) { let enoughMiscItems = true; for (const ingredient of meta.ingredients) { diff --git a/src/services/guildService.ts b/src/services/guildService.ts index edf07ce1..87e2f721 100644 --- a/src/services/guildService.ts +++ b/src/services/guildService.ts @@ -550,6 +550,19 @@ export const processFundedGuildTechProject = ( guild.XP += recipe.guildXpValue; } setGuildTechLogState(guild, techProject.ItemType, config.noDojoResearchTime ? 4 : 3, techProject.CompletionDate); + if (config.noDojoResearchTime) { + processCompletedGuildTechProject(guild, techProject.ItemType); + } +}; + +export const processCompletedGuildTechProject = (guild: TGuildDatabaseDocument, type: string): void => { + if (type.startsWith("/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/")) { + guild.VaultDecoRecipes ??= []; + guild.VaultDecoRecipes.push({ + ItemType: type, + ItemCount: 1 + }); + } }; export const setGuildTechLogState = ( diff --git a/src/services/shipCustomizationsService.ts b/src/services/shipCustomizationsService.ts index 990fa13e..c815dc56 100644 --- a/src/services/shipCustomizationsService.ts +++ b/src/services/shipCustomizationsService.ts @@ -64,8 +64,12 @@ export const handleSetShipDecorations = async ( throw new Error(`unknown room: ${placedDecoration.Room}`); } - const [itemType, meta] = Object.entries(ExportResources).find(arr => arr[1].deco == placedDecoration.Type)!; - if (!itemType || meta.capacityCost === undefined) { + const entry = Object.entries(ExportResources).find(arr => arr[1].deco == placedDecoration.Type); + if (!entry) { + throw new Error(`unknown deco type: ${placedDecoration.Type}`); + } + const [itemType, meta] = entry; + if (meta.capacityCost === undefined) { throw new Error(`unknown deco type: ${placedDecoration.Type}`); } diff --git a/static/fixed_responses/allDecoRecipes.json b/static/fixed_responses/allDecoRecipes.json index efbbeed2..471f7ae3 100644 --- a/static/fixed_responses/allDecoRecipes.json +++ b/static/fixed_responses/allDecoRecipes.json @@ -92,5 +92,13 @@ "/Lotus/Levels/ClanDojo/ComponentPropRecipes/ThumperTrophySilverRecipe", "/Lotus/Levels/ClanDojo/ComponentPropRecipes/CorpusPlaceables/GasTurbineConeRecipe", "/Lotus/Levels/ClanDojo/ComponentPropRecipes/NaturalPlaceables/CoralChunkARecipe", - "/Lotus/Levels/ClanDojo/ComponentPropRecipes/TennoPlaceables/TnoBeaconEmitterRecipe" + "/Lotus/Levels/ClanDojo/ComponentPropRecipes/TennoPlaceables/TnoBeaconEmitterRecipe", + "/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/OstronFemaleSitting", + "/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/OstronFemaleStanding", + "/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/OstronMaleStanding", + "/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/OstronMaleStandingTwo", + "/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/SolarisForeman", + "/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/SolarisHazard", + "/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/SolarisStrikerOne", + "/Lotus/Levels/ClanDojo/ComponentPropRecipes/NpcPlaceables/SolarisStrikerThree" ] From 1d60745f188967755ec38be52baed1bd1b95e08b Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:45:41 -0700 Subject: [PATCH 6/7] feat: year rollover kiss emails (#2376) Closes #2375 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2376 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/api/inventoryController.ts | 52 ++++++++++++++++++++++ src/models/inboxModel.ts | 4 ++ src/services/inventoryService.ts | 19 +++++++- src/services/itemDataService.ts | 2 + 4 files changed, 75 insertions(+), 2 deletions(-) diff --git a/src/controllers/api/inventoryController.ts b/src/controllers/api/inventoryController.ts index cb855f16..c1933a80 100644 --- a/src/controllers/api/inventoryController.ts +++ b/src/controllers/api/inventoryController.ts @@ -9,6 +9,7 @@ import { IPolarity, ArtifactPolarity, EquipmentFeatures } from "@/src/types/inve import { ExportCustoms, ExportFlavour, ExportResources, ExportVirtuals } from "warframe-public-export-plus"; import { applyCheatsToInfestedFoundry, handleSubsumeCompletion } from "@/src/services/infestedFoundryService"; import { + addEmailItem, addMiscItems, allDailyAffiliationKeys, cleanupInventory, @@ -110,7 +111,58 @@ export const inventoryController: RequestHandler = async (request, response) => } if (inventory.CalendarProgress) { + const previousYearIteration = inventory.CalendarProgress.Iteration; getCalendarProgress(inventory); // handle year rollover; the client expects to receive an inventory with an up-to-date CalendarProgress + + // also handle sending of kiss cinematic at year rollover + if ( + inventory.CalendarProgress.Iteration != previousYearIteration && + inventory.DialogueHistory && + inventory.DialogueHistory.Dialogues + ) { + let kalymos = false; + for (const { dialogueName, kissEmail } of [ + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/ArthurKissEmailItem" + }, + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/EleanorDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/EleanorKissEmailItem" + }, + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/LettieKissEmailItem" + }, + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/AmirKissEmailItem" + }, + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/AoiDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/AoiKissEmailItem" + }, + { + dialogueName: "/Lotus/Types/Gameplay/1999Wf/Dialogue/QuincyDialogue_rom.dialogue", + kissEmail: "/Lotus/Types/Items/EmailItems/QuincyKissEmailItem" + } + ]) { + const dialogue = inventory.DialogueHistory.Dialogues.find(x => x.DialogueName == dialogueName); + if (dialogue) { + if (dialogue.Rank == 7) { + await addEmailItem(inventory, kissEmail); + kalymos = false; + break; + } + if (dialogue.Rank == 6) { + kalymos = true; + } + } + } + if (kalymos) { + await addEmailItem(inventory, "/Lotus/Types/Items/EmailItems/KalymosKissEmailItem"); + } + } } cleanupInventory(inventory); diff --git a/src/models/inboxModel.ts b/src/models/inboxModel.ts index 139e8b44..793d37d8 100644 --- a/src/models/inboxModel.ts +++ b/src/models/inboxModel.ts @@ -23,7 +23,9 @@ export interface IMessageDatabase extends IMessage { export interface IMessage { sndr: string; msg: string; + cinematic?: string; sub: string; + customData?: string; icon?: string; highPriority?: boolean; lowPrioNewPlayers?: boolean; @@ -102,7 +104,9 @@ const messageSchema = new Schema( ownerId: Schema.Types.ObjectId, sndr: String, msg: String, + cinematic: String, sub: String, + customData: String, icon: String, highPriority: Boolean, lowPrioNewPlayers: Boolean, diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index df9ac473..3bfb3244 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -83,7 +83,7 @@ import { addQuestKey, completeQuest } from "@/src/services/questService"; import { handleBundleAcqusition } from "./purchaseService"; import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json"; import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService"; -import { createMessage } from "./inboxService"; +import { createMessage, IMessageCreationTemplate } from "./inboxService"; import { getMaxStanding, getMinStanding } from "@/src/helpers/syndicateStandingHelper"; import { getNightwaveSyndicateTag, getWorldState } from "./worldStateService"; import { ICalendarSeason } from "@/src/types/worldStateTypes"; @@ -1563,7 +1563,22 @@ export const addEmailItem = async ( const meta = ExportEmailItems[typeName]; const emailItem = inventory.EmailItems.find(x => x.ItemType == typeName); if (!emailItem || !meta.sendOnlyOnce) { - await createMessage(inventory.accountOwnerId, [convertInboxMessage(meta.message)]); + const msg: IMessageCreationTemplate = convertInboxMessage(meta.message); + if (msg.cinematic == "/Lotus/Levels/1999/PlayerHomeBalconyCinematics.level") { + msg.customData = JSON.stringify({ + Tag: msg.customData + "KissCin", + CinLoadout: { + Skins: inventory.AdultOperatorLoadOuts[0].Skins, + Upgrades: inventory.AdultOperatorLoadOuts[0].Upgrades, + attcol: inventory.AdultOperatorLoadOuts[0].attcol, + cloth: inventory.AdultOperatorLoadOuts[0].cloth, + eyecol: inventory.AdultOperatorLoadOuts[0].eyecol, + pricol: inventory.AdultOperatorLoadOuts[0].pricol, + syancol: inventory.AdultOperatorLoadOuts[0].syancol + } + }); + } + await createMessage(inventory.accountOwnerId, [msg]); if (emailItem) { emailItem.ItemCount += 1; diff --git a/src/services/itemDataService.ts b/src/services/itemDataService.ts index c44691f5..e028e8c0 100644 --- a/src/services/itemDataService.ts +++ b/src/services/itemDataService.ts @@ -251,7 +251,9 @@ export const convertInboxMessage = (message: IInboxMessage): IMessage => { return { sndr: message.sender, msg: message.body, + cinematic: message.cinematic, sub: message.title, + customData: message.customData, att: message.attachments.length > 0 ? message.attachments : undefined, countedAtt: message.countedAttachments.length > 0 ? message.countedAttachments : undefined, icon: message.icon ?? "", From 363028c9ce4a5c99f8670360754e4345ae846d71 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Tue, 1 Jul 2025 07:48:03 -0700 Subject: [PATCH 7/7] chore: clarify log output related to saveLoadout (#2379) Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/2379 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/services/saveLoadoutService.ts | 9 +++++++-- 1 file changed, 7 insertions(+), 2 deletions(-) diff --git a/src/services/saveLoadoutService.ts b/src/services/saveLoadoutService.ts index ff42ad82..5b35d079 100644 --- a/src/services/saveLoadoutService.ts +++ b/src/services/saveLoadoutService.ts @@ -167,8 +167,13 @@ export const handleInventoryItemConfigChange = async ( inventory.LotusCustomization = equipmentChanges.LotusCustomization; break; } + case "ValidNewLoadoutId": { + logger.debug(`ignoring ValidNewLoadoutId (${equipmentChanges.ValidNewLoadoutId})`); + // seems always equal to the id of loadout config NORMAL[0], likely has no purpose and we're free to ignore it + break; + } default: { - if (equipmentKeys.includes(equipmentName as TEquipmentKey) && equipmentName != "ValidNewLoadoutId") { + if (equipmentKeys.includes(equipmentName as TEquipmentKey)) { logger.debug(`general Item config saved of type ${equipmentName}`, { config: equipment }); @@ -216,7 +221,7 @@ export const handleInventoryItemConfigChange = async ( } break; } else { - logger.warn(`loadout category not implemented, changes may be lost: ${equipmentName}`, { + logger.error(`loadout category not implemented, changes will be lost: ${equipmentName}`, { config: equipment }); }