From 66e34b7be9160dcb017f1aa590a6fdf1d60025a7 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Thu, 17 Apr 2025 07:59:42 -0700 Subject: [PATCH 1/6] feat: identify & repair railjack armaments (#1686) Closes #1676 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1686 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- .../api/crewShipIdentifySalvageController.ts | 69 ++++++++++++++----- src/controllers/api/guildTechController.ts | 28 ++++++-- src/services/inventoryService.ts | 2 +- 3 files changed, 72 insertions(+), 27 deletions(-) diff --git a/src/controllers/api/crewShipIdentifySalvageController.ts b/src/controllers/api/crewShipIdentifySalvageController.ts index d9d09b75..6cde1cda 100644 --- a/src/controllers/api/crewShipIdentifySalvageController.ts +++ b/src/controllers/api/crewShipIdentifySalvageController.ts @@ -1,33 +1,64 @@ -import { addCrewShipSalvagedWeaponSkin, addCrewShipRawSalvage, getInventory } from "@/src/services/inventoryService"; +import { + addCrewShipSalvagedWeaponSkin, + addCrewShipRawSalvage, + getInventory, + addEquipment +} from "@/src/services/inventoryService"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { RequestHandler } from "express"; -import { ICrewShipComponentFingerprint } from "@/src/types/inventoryTypes/inventoryTypes"; -import { ExportCustoms } from "warframe-public-export-plus"; +import { ICrewShipComponentFingerprint, IInnateDamageFingerprint } from "@/src/types/inventoryTypes/inventoryTypes"; +import { ExportCustoms, ExportRailjackWeapons, ExportUpgrades } from "warframe-public-export-plus"; import { getJSONfromString } from "@/src/helpers/stringHelpers"; import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { getRandomInt } from "@/src/services/rngService"; +import { IFingerprintStat } from "@/src/helpers/rivenHelper"; export const crewShipIdentifySalvageController: RequestHandler = async (req, res) => { const accountId = await getAccountIdForRequest(req); - const inventory = await getInventory(accountId, "CrewShipSalvagedWeaponSkins CrewShipRawSalvage"); + const inventory = await getInventory( + accountId, + "CrewShipSalvagedWeaponSkins CrewShipSalvagedWeapons CrewShipRawSalvage" + ); const payload = getJSONfromString(String(req.body)); - const meta = ExportCustoms[payload.ItemType]; - let upgradeFingerprint: ICrewShipComponentFingerprint = { compat: payload.ItemType, buffs: [] }; - if (meta.subroutines) { - upgradeFingerprint = { - SubroutineIndex: getRandomInt(0, meta.subroutines.length - 1), - ...upgradeFingerprint - }; + const inventoryChanges: IInventoryChanges = {}; + if (payload.ItemType in ExportCustoms) { + const meta = ExportCustoms[payload.ItemType]; + let upgradeFingerprint: ICrewShipComponentFingerprint = { compat: payload.ItemType, buffs: [] }; + if (meta.subroutines) { + upgradeFingerprint = { + SubroutineIndex: getRandomInt(0, meta.subroutines.length - 1), + ...upgradeFingerprint + }; + } + for (const upgrade of meta.randomisedUpgrades!) { + upgradeFingerprint.buffs.push({ Tag: upgrade.tag, Value: Math.trunc(Math.random() * 0x40000000) }); + } + addCrewShipSalvagedWeaponSkin( + inventory, + payload.ItemType, + JSON.stringify(upgradeFingerprint), + inventoryChanges + ); + } else { + const meta = ExportRailjackWeapons[payload.ItemType]; + const upgradeType = meta.defaultUpgrades![0].ItemType; + const upgradeMeta = ExportUpgrades[upgradeType]; + const buffs: IFingerprintStat[] = []; + for (const buff of upgradeMeta.upgradeEntries!) { + buffs.push({ + Tag: buff.tag, + Value: Math.trunc(Math.random() * 0x40000000) + }); + } + addEquipment(inventory, "CrewShipSalvagedWeapons", payload.ItemType, undefined, inventoryChanges, { + UpgradeType: upgradeType, + UpgradeFingerprint: JSON.stringify({ + compat: payload.ItemType, + buffs + } satisfies IInnateDamageFingerprint) + }); } - for (const upgrade of meta.randomisedUpgrades!) { - upgradeFingerprint.buffs.push({ Tag: upgrade.tag, Value: Math.trunc(Math.random() * 0x40000000) }); - } - const inventoryChanges: IInventoryChanges = addCrewShipSalvagedWeaponSkin( - inventory, - payload.ItemType, - JSON.stringify(upgradeFingerprint) - ); inventoryChanges.CrewShipRawSalvage = [ { diff --git a/src/controllers/api/guildTechController.ts b/src/controllers/api/guildTechController.ts index 57370d75..ebfd40ea 100644 --- a/src/controllers/api/guildTechController.ts +++ b/src/controllers/api/guildTechController.ts @@ -15,6 +15,7 @@ import { ExportDojoRecipes } from "warframe-public-export-plus"; import { getAccountIdForRequest } from "@/src/services/loginService"; import { addCrewShipWeaponSkin, + addEquipment, addItem, addMiscItems, addRecipes, @@ -382,18 +383,31 @@ interface IGuildTechContributeRequest { const claimSalvagedComponent = (inventory: TInventoryDatabaseDocument, itemId: string): IInventoryChanges => { // delete personal tech project const personalTechProjectIndex = inventory.PersonalTechProjects.findIndex(x => x.CategoryItemId?.equals(itemId)); - if (personalTechProjectIndex != -1) { - inventory.PersonalTechProjects.splice(personalTechProjectIndex, 1); - } + const personalTechProject = inventory.PersonalTechProjects[personalTechProjectIndex]; + inventory.PersonalTechProjects.splice(personalTechProjectIndex, 1); + + const category = personalTechProject.ProductCategory! as "CrewShipWeapons" | "CrewShipWeaponSkins"; + const salvageCategory = category == "CrewShipWeapons" ? "CrewShipSalvagedWeapons" : "CrewShipSalvagedWeaponSkins"; // find salved part & delete it - const crewShipSalvagedWeaponSkinsIndex = inventory.CrewShipSalvagedWeaponSkins.findIndex(x => x._id.equals(itemId)); - const crewShipWeaponSkin = inventory.CrewShipSalvagedWeaponSkins[crewShipSalvagedWeaponSkinsIndex]; - inventory.CrewShipSalvagedWeaponSkins.splice(crewShipSalvagedWeaponSkinsIndex, 1); + const salvageIndex = inventory[salvageCategory].findIndex(x => x._id.equals(itemId)); + const salvageItem = inventory[category][salvageIndex]; + inventory[salvageCategory].splice(salvageIndex, 1); // add final item const inventoryChanges = { - ...addCrewShipWeaponSkin(inventory, crewShipWeaponSkin.ItemType, crewShipWeaponSkin.UpgradeFingerprint), + ...(category == "CrewShipWeaponSkins" + ? addCrewShipWeaponSkin(inventory, salvageItem.ItemType, salvageItem.UpgradeFingerprint) + : addEquipment( + inventory, + category, + salvageItem.ItemType, + undefined, + {}, + { + UpgradeFingerprint: salvageItem.UpgradeFingerprint + } + )), ...occupySlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS, false) }; diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 71dfa9d1..2dd4c0d3 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -1083,7 +1083,7 @@ export const addEquipment = ( Configs: [], XP: 0, ModularParts: modularParts, - IsNew: category != "CrewShipWeapons" ? true : undefined + IsNew: category != "CrewShipWeapons" && category != "CrewShipSalvagedWeapons" ? true : undefined }, defaultOverwrites ); From 8a1603a661becd0fbea3d5b13fa5351a027280b5 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Thu, 17 Apr 2025 07:59:57 -0700 Subject: [PATCH 2/6] feat: more comprehensive handling of railjack items in sellController (#1687) Closes #1675 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1687 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 | 108 +++++++++++++++++++++----- 1 file changed, 90 insertions(+), 18 deletions(-) diff --git a/src/controllers/api/sellController.ts b/src/controllers/api/sellController.ts index f6840589..138cd3b4 100644 --- a/src/controllers/api/sellController.ts +++ b/src/controllers/api/sellController.ts @@ -7,16 +7,18 @@ import { addMiscItems, addConsumables, freeUpSlot, - combineInventoryChanges + combineInventoryChanges, + addCrewShipRawSalvage } from "@/src/services/inventoryService"; import { InventorySlot } from "@/src/types/inventoryTypes/inventoryTypes"; import { ExportDojoRecipes } from "warframe-public-export-plus"; import { IInventoryChanges } from "@/src/types/purchaseTypes"; +import { TInventoryDatabaseDocument } from "@/src/models/inventoryModels/inventoryModel"; export const sellController: RequestHandler = async (req, res) => { const payload = JSON.parse(String(req.body)) as ISellRequest; const accountId = await getAccountIdForRequest(req); - const requiredFields = new Set(); + const requiredFields = new Set(); if (payload.SellCurrency == "SC_RegularCredits") { requiredFields.add("RegularCredits"); } else if (payload.SellCurrency == "SC_FusionPoints") { @@ -25,7 +27,7 @@ export const sellController: RequestHandler = async (req, res) => { requiredFields.add("MiscItems"); } for (const key of Object.keys(payload.Items)) { - requiredFields.add(key); + requiredFields.add(key as keyof TInventoryDatabaseDocument); } if (requiredFields.has("Upgrades")) { requiredFields.add("RawUpgrades"); @@ -51,8 +53,15 @@ export const sellController: RequestHandler = async (req, res) => { if (payload.Items.Hoverboards) { requiredFields.add(InventorySlot.SPACESUITS); } - if (payload.Items.CrewShipWeapons) { + if (payload.Items.CrewShipWeapons || payload.Items.CrewShipWeaponSkins) { requiredFields.add(InventorySlot.RJ_COMPONENT_AND_ARMAMENTS); + requiredFields.add("CrewShipRawSalvage"); + if (payload.Items.CrewShipWeapons) { + requiredFields.add("CrewShipSalvagedWeapons"); + } + if (payload.Items.CrewShipWeaponSkins) { + requiredFields.add("CrewShipSalvagedWeaponSkins"); + } } const inventory = await getInventory(accountId, Array.from(requiredFields).join(" ")); @@ -76,7 +85,7 @@ export const sellController: RequestHandler = async (req, res) => { } ]); } else if (payload.SellCurrency == "SC_Resources") { - // Will add appropriate MiscItems from CrewShipWeapons + // Will add appropriate MiscItems from CrewShipWeapons or CrewShipWeaponSkins } else { throw new Error("Unknown SellCurrency: " + payload.SellCurrency); } @@ -157,19 +166,51 @@ export const sellController: RequestHandler = async (req, res) => { } if (payload.Items.CrewShipWeapons) { payload.Items.CrewShipWeapons.forEach(sellItem => { - const index = inventory.CrewShipWeapons.findIndex(x => x._id.equals(sellItem.String)); - if (index != -1) { - const itemType = inventory.CrewShipWeapons[index].ItemType; - const recipe = Object.values(ExportDojoRecipes.fabrications).find(x => x.resultType == itemType)!; - const miscItemChanges = recipe.ingredients.map(x => ({ - ItemType: x.ItemType, - ItemCount: Math.trunc(x.ItemCount * 0.8) - })); - addMiscItems(inventory, miscItemChanges); - combineInventoryChanges(inventoryChanges, { MiscItems: miscItemChanges }); - - inventory.CrewShipWeapons.splice(index, 1); - freeUpSlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS); + if (sellItem.String[0] == "/") { + addCrewShipRawSalvage(inventory, [ + { + ItemType: sellItem.String, + ItemCount: sellItem.Count * -1 + } + ]); + } else { + const index = inventory.CrewShipWeapons.findIndex(x => x._id.equals(sellItem.String)); + if (index != -1) { + if (payload.SellCurrency == "SC_Resources") { + refundPartialBuildCosts(inventory, inventory.CrewShipWeapons[index].ItemType, inventoryChanges); + } + inventory.CrewShipWeapons.splice(index, 1); + freeUpSlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS); + } else { + inventory.CrewShipSalvagedWeapons.pull({ _id: sellItem.String }); + } + } + }); + } + if (payload.Items.CrewShipWeaponSkins) { + payload.Items.CrewShipWeaponSkins.forEach(sellItem => { + if (sellItem.String[0] == "/") { + addCrewShipRawSalvage(inventory, [ + { + ItemType: sellItem.String, + ItemCount: sellItem.Count * -1 + } + ]); + } else { + const index = inventory.CrewShipWeaponSkins.findIndex(x => x._id.equals(sellItem.String)); + if (index != -1) { + if (payload.SellCurrency == "SC_Resources") { + refundPartialBuildCosts( + inventory, + inventory.CrewShipWeaponSkins[index].ItemType, + inventoryChanges + ); + } + inventory.CrewShipWeaponSkins.splice(index, 1); + freeUpSlot(inventory, InventorySlot.RJ_COMPONENT_AND_ARMAMENTS); + } else { + inventory.CrewShipSalvagedWeaponSkins.pull({ _id: sellItem.String }); + } } }); } @@ -243,6 +284,7 @@ interface ISellRequest { Hoverboards?: ISellItem[]; Drones?: ISellItem[]; CrewShipWeapons?: ISellItem[]; + CrewShipWeaponSkins?: ISellItem[]; }; SellPrice: number; SellCurrency: @@ -259,3 +301,33 @@ interface ISellItem { String: string; // oid or uniqueName Count: number; } + +const refundPartialBuildCosts = ( + inventory: TInventoryDatabaseDocument, + itemType: string, + inventoryChanges: IInventoryChanges +): void => { + // House versions + const research = Object.values(ExportDojoRecipes.research).find(x => x.resultType == itemType); + if (research) { + const miscItemChanges = research.ingredients.map(x => ({ + ItemType: x.ItemType, + ItemCount: Math.trunc(x.ItemCount * 0.8) + })); + addMiscItems(inventory, miscItemChanges); + combineInventoryChanges(inventoryChanges, { MiscItems: miscItemChanges }); + return; + } + + // Sigma versions + const recipe = Object.values(ExportDojoRecipes.fabrications).find(x => x.resultType == itemType); + if (recipe) { + const miscItemChanges = recipe.ingredients.map(x => ({ + ItemType: x.ItemType, + ItemCount: Math.trunc(x.ItemCount * 0.8) + })); + addMiscItems(inventory, miscItemChanges); + combineInventoryChanges(inventoryChanges, { MiscItems: miscItemChanges }); + return; + } +}; From 435aafeaaeb9ceaecc7336d74b796b52ac2e62ff Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Thu, 17 Apr 2025 08:00:19 -0700 Subject: [PATCH 3/6] feat: randomly generate 1999 calendar seasons (#1689) also handling week rollover now Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1689 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/services/worldStateService.ts | 225 ++++++++++++++++-- src/types/worldStateTypes.ts | 20 +- .../worldState/1999_fall_days.json | 77 ------ .../worldState/1999_spring_days.json | 75 ------ .../worldState/1999_summer_days.json | 75 ------ .../worldState/1999_winter_days.json | 75 ------ .../worldState/worldState.json | 87 +------ 7 files changed, 227 insertions(+), 407 deletions(-) delete mode 100644 static/fixed_responses/worldState/1999_fall_days.json delete mode 100644 static/fixed_responses/worldState/1999_spring_days.json delete mode 100644 static/fixed_responses/worldState/1999_summer_days.json delete mode 100644 static/fixed_responses/worldState/1999_winter_days.json diff --git a/src/services/worldStateService.ts b/src/services/worldStateService.ts index 55f6afd9..ed65a8fc 100644 --- a/src/services/worldStateService.ts +++ b/src/services/worldStateService.ts @@ -1,14 +1,10 @@ import staticWorldState from "@/static/fixed_responses/worldState/worldState.json"; -import static1999FallDays from "@/static/fixed_responses/worldState/1999_fall_days.json"; -import static1999SpringDays from "@/static/fixed_responses/worldState/1999_spring_days.json"; -import static1999SummerDays from "@/static/fixed_responses/worldState/1999_summer_days.json"; -import static1999WinterDays from "@/static/fixed_responses/worldState/1999_winter_days.json"; import { buildConfig } from "@/src/services/buildConfigService"; import { unixTimesInMs } from "@/src/constants/timeConstants"; import { config } from "@/src/services/configService"; import { CRng } from "@/src/services/rngService"; import { eMissionType, ExportNightwave, ExportRegions } from "warframe-public-export-plus"; -import { ISeasonChallenge, ISortie, IWorldState } from "../types/worldStateTypes"; +import { ICalendarDay, ICalendarSeason, ISeasonChallenge, ISortie, IWorldState } from "../types/worldStateTypes"; const sortieBosses = [ "SORTIE_BOSS_HYENA", @@ -352,6 +348,209 @@ const getSeasonWeeklyHardChallenge = (week: number, id: number): ISeasonChalleng }; }; +const birthdays: number[] = [ + 1, // Kaya + 45, // Lettie + 74, // Minerva (MinervaVelemirDialogue_rom.dialogue) + 143, // Amir + 166, // Flare + 191, // Aoi + 306, // Eleanor + 307, // Arthur + 338, // Quincy + 355 // Velimir (MinervaVelemirDialogue_rom.dialogue) +]; + +const getCalendarSeason = (week: number): ICalendarSeason => { + const seasonIndex = week % 4; + const seasonDay1 = seasonIndex * 90 + 1; + const seasonDay91 = seasonIndex * 90 + 91; + const eventDays: ICalendarDay[] = []; + for (const day of birthdays) { + if (day < seasonDay1) { + continue; + } + if (day >= seasonDay91) { + break; + } + //logger.debug(`birthday on day ${day}`); + eventDays.push({ day, events: [] }); // This is how CET_PLOT looks in worldState as of around 38.5.0 + } + const rng = new CRng(week); + const challenges = [ + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithMeleeEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithMeleeMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithMeleeHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithAbilitiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithAbilitiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithAbilitiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEximusEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEximusMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillEximusHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithAbilitiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithAbilitiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithAbilitiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTankHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithMeleeEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithMeleeMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithMeleeHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithAbilitiesEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithAbilitiesMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithAbilitiesHard", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithMeleeEasy", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithMeleeMedium", + "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithMeleeHard" + ]; + const rewardRanges: number[] = []; + const upgradeRanges: number[] = []; + for (let i = 0; i != 6; ++i) { + const chunkDay1 = seasonDay1 + i * 15; + const chunkDay13 = chunkDay1 - 1 + 13; + let challengeDay: number; + do { + challengeDay = rng.randomInt(chunkDay1, chunkDay13); + } while (birthdays.indexOf(challengeDay) != -1); + + const challengeIndex = rng.randomInt(0, challenges.length - 1); + const challenge = challenges[challengeIndex]; + challenges.splice(challengeIndex, 1); + + //logger.debug(`challenge on day ${challengeDay}`); + eventDays.push({ + day: challengeDay, + events: [{ type: "CET_CHALLENGE", challenge }] + }); + + rewardRanges.push(challengeDay); + if (i == 0 || i == 3 || i == 5) { + upgradeRanges.push(challengeDay); + } + } + rewardRanges.push(seasonDay91); + upgradeRanges.push(seasonDay91); + + const rewards = [ + "/Lotus/StoreItems/Types/Items/MiscItems/UtilityUnlocker", + "/Lotus/StoreItems/Types/Recipes/Components/FormaAuraBlueprint", + "/Lotus/StoreItems/Types/Recipes/Components/FormaBlueprint", + "/Lotus/StoreItems/Types/Recipes/Components/WeaponUtilityUnlockerBlueprint", + "/Lotus/StoreItems/Types/Items/MiscItems/WeaponMeleeArcaneUnlocker", + "/Lotus/StoreItems/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker", + "/Lotus/StoreItems/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker", + "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CircuitSilverSteelPathFusionBundle", + "/Lotus/StoreItems/Types/BoosterPacks/CalendarRivenPack", + "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleSmall", + "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleLarge", + "/Lotus/StoreItems/Types/BoosterPacks/CalendarArtifactPack", + "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack", + "/Lotus/Types/StoreItems/Boosters/AffinityBooster3DayStoreItem", + "/Lotus/Types/StoreItems/Boosters/ModDropChanceBooster3DayStoreItem", + "/Lotus/Types/StoreItems/Boosters/ResourceDropChance3DayStoreItem", + "/Lotus/StoreItems/Types/Items/MiscItems/Forma", + "/Lotus/StoreItems/Types/Recipes/Components/OrokinCatalystBlueprint", + "/Lotus/StoreItems/Types/Recipes/Components/OrokinReactorBlueprint", + "/Lotus/StoreItems/Types/Items/MiscItems/WeaponUtilityUnlocker", + "/Lotus/Types/StoreItems/Packages/Calendar/CalendarVosforPack", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalOrange", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalNira", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalGreen", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalBoreal", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalAmar", + "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalViolet" + ]; + for (let i = 0; i != rewardRanges.length - 1; ++i) { + const rewardIndex = rng.randomInt(0, rewards.length - 1); + const reward = rewards[rewardIndex]; + rewards.splice(rewardIndex, 1); + + //logger.debug(`trying to fit a reward between day ${rewardRanges[i]} and ${rewardRanges[i + 1]}`); + let day: number; + do { + day = rng.randomInt(rewardRanges[i] + 1, rewardRanges[i + 1] - 1); + } while (eventDays.find(x => x.day == day)); + eventDays.push({ day, events: [{ type: "CET_REWARD", reward }] }); + } + + const upgrades = [ + "/Lotus/Upgrades/Calendar/MeleeCritChance", + "/Lotus/Upgrades/Calendar/MeleeAttackSpeed", + "/Lotus/Upgrades/Calendar/EnergyOrbToAbilityRange", + "/Lotus/Upgrades/Calendar/AbilityStrength", + "/Lotus/Upgrades/Calendar/Armor", + "/Lotus/Upgrades/Calendar/RadiationProcOnTakeDamage", + "/Lotus/Upgrades/Calendar/CompanionDamage", + "/Lotus/Upgrades/Calendar/GasChanceToPrimaryAndSecondary", + "/Lotus/Upgrades/Calendar/MagazineCapacity", + "/Lotus/Upgrades/Calendar/PunchToPrimary", + "/Lotus/Upgrades/Calendar/HealingEffects", + "/Lotus/Upgrades/Calendar/EnergyRestoration", + "/Lotus/Upgrades/Calendar/OvershieldCap", + "/Lotus/Upgrades/Calendar/ElectricStatusDamageAndChance", + "/Lotus/Upgrades/Calendar/FinisherChancePerComboMultiplier", + "/Lotus/Upgrades/Calendar/MagnetStatusPull", + "/Lotus/Upgrades/Calendar/CompanionsBuffNearbyPlayer", + "/Lotus/Upgrades/Calendar/StatusChancePerAmmoSpent", + "/Lotus/Upgrades/Calendar/OrbsDuplicateOnPickup", + "/Lotus/Upgrades/Calendar/AttackAndMovementSpeedOnCritMelee", + "/Lotus/Upgrades/Calendar/RadialJavelinOnHeavy", + "/Lotus/Upgrades/Calendar/MagnitizeWithinRangeEveryXCasts", + "/Lotus/Upgrades/Calendar/CompanionsRadiationChance", + "/Lotus/Upgrades/Calendar/BlastEveryXShots", + "/Lotus/Upgrades/Calendar/GenerateOmniOrbsOnWeakKill", + "/Lotus/Upgrades/Calendar/ElectricDamagePerDistance", + "/Lotus/Upgrades/Calendar/MeleeSlideFowardMomentumOnEnemyHit", + "/Lotus/Upgrades/Calendar/SharedFreeAbilityEveryXCasts", + "/Lotus/Upgrades/Calendar/ReviveEnemyAsSpectreOnKill", + "/Lotus/Upgrades/Calendar/RefundBulletOnStatusProc", + "/Lotus/Upgrades/Calendar/ExplodingHealthOrbs", + "/Lotus/Upgrades/Calendar/SpeedBuffsWhenAirborne", + "/Lotus/Upgrades/Calendar/EnergyWavesOnCombo", + "/Lotus/Upgrades/Calendar/PowerStrengthAndEfficiencyPerEnergySpent", + "/Lotus/Upgrades/Calendar/CloneActiveCompanionForEnergySpent", + "/Lotus/Upgrades/Calendar/GuidingMissilesChance", + "/Lotus/Upgrades/Calendar/EnergyOrbsGrantShield", + "/Lotus/Upgrades/Calendar/ElectricalDamageOnBulletJump" + ]; + for (let i = 0; i != upgradeRanges.length - 1; ++i) { + const upgradeIndex = rng.randomInt(0, upgrades.length - 1); + const upgrade = upgrades[upgradeIndex]; + upgrades.splice(upgradeIndex, 1); + + //logger.debug(`trying to fit an upgrade between day ${upgradeRanges[i]} and ${upgradeRanges[i + 1]}`); + let day: number; + do { + day = rng.randomInt(upgradeRanges[i] + 1, upgradeRanges[i + 1] - 1); + } while (eventDays.find(x => x.day == day)); + eventDays.push({ day, events: [{ type: "CET_UPGRADE", upgrade }] }); + } + + eventDays.sort((a, b) => a.day - b.day); + + const weekStart = EPOCH + week * 604800000; + const weekEnd = weekStart + 604800000; + return { + Activation: { $date: { $numberLong: weekStart.toString() } }, + Expiry: { $date: { $numberLong: weekEnd.toString() } }, + Days: eventDays, + Season: ["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"][seasonIndex], + YearIteration: Math.trunc(week / 4), + Version: 19, + UpgradeAvaliabilityRequirements: ["/Lotus/Upgrades/Calendar/1999UpgradeApplicationRequirement"] + }; +}; + export const getWorldState = (buildLabel?: string): IWorldState => { const day = Math.trunc((Date.now() - EPOCH) / 86400000); const week = Math.trunc(day / 7); @@ -376,6 +575,7 @@ export const getWorldState = (buildLabel?: string): IWorldState => { Params: "", ActiveChallenges: [] }, + KnownCalendarSeasons: [], ...staticWorldState, SyndicateMissions: [...staticWorldState.SyndicateMissions] }; @@ -834,17 +1034,10 @@ export const getWorldState = (buildLabel?: string): IWorldState => { }); // 1999 Calendar Season cycling every week + YearIteration every 4 weeks - // TODO: Handle imminent rollover - worldState.KnownCalendarSeasons[0].Activation = { $date: { $numberLong: weekStart.toString() } }; - worldState.KnownCalendarSeasons[0].Expiry = { $date: { $numberLong: weekEnd.toString() } }; - worldState.KnownCalendarSeasons[0].Season = ["CST_WINTER", "CST_SPRING", "CST_SUMMER", "CST_FALL"][week % 4]; - worldState.KnownCalendarSeasons[0].Days = [ - static1999WinterDays, - static1999SpringDays, - static1999SummerDays, - static1999FallDays - ][week % 4]; - worldState.KnownCalendarSeasons[0].YearIteration = Math.trunc(week / 4); + worldState.KnownCalendarSeasons.push(getCalendarSeason(week)); + if (isBeforeNextExpectedWorldStateRefresh(weekEnd)) { + worldState.KnownCalendarSeasons.push(getCalendarSeason(week + 1)); + } // Sentient Anomaly cycling every 30 minutes const halfHour = Math.trunc(Date.now() / (unixTimesInMs.hour / 2)); diff --git a/src/types/worldStateTypes.ts b/src/types/worldStateTypes.ts index aaa292e4..278f6e95 100644 --- a/src/types/worldStateTypes.ts +++ b/src/types/worldStateTypes.ts @@ -127,8 +127,22 @@ export interface ICalendarSeason { Activation: IMongoDate; Expiry: IMongoDate; Season: string; // "CST_UNDEFINED" | "CST_WINTER" | "CST_SPRING" | "CST_SUMMER" | "CST_FALL" - Days: { - day: number; - }[]; + Days: ICalendarDay[]; YearIteration: number; + Version: number; + UpgradeAvaliabilityRequirements: string[]; +} + +export interface ICalendarDay { + day: number; + events: ICalendarEvent[]; +} + +export interface ICalendarEvent { + type: string; + challenge?: string; + reward?: string; + upgrade?: string; + dialogueName?: string; + dialogueConvo?: string; } diff --git a/static/fixed_responses/worldState/1999_fall_days.json b/static/fixed_responses/worldState/1999_fall_days.json deleted file mode 100644 index 3bcd30eb..00000000 --- a/static/fixed_responses/worldState/1999_fall_days.json +++ /dev/null @@ -1,77 +0,0 @@ -[ - { "day": 276, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesEasy" }] }, - { - "day": 283, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/CompanionDamage" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/GasChanceToPrimaryAndSecondary" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/ElectricStatusDamageAndChance" } - ] - }, - { - "day": 289, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponUtilityUnlocker" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack" } - ] - }, - { "day": 295, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithMeleeEasy" }] }, - { - "day": 302, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker" } - ] - }, - { "day": 305, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillEximusMedium" }] }, - { "day": 306, "events": [{ "type": "CET_PLOT", "dialogueName": "/Lotus/Types/Gameplay/1999Wf/Dialogue/EleanorDialogue_rom.dialogue", "dialogueConvo": "EleanorBirthdayConvo" }] }, - { "day": 307, "events": [{ "type": "CET_PLOT", "dialogueName": "/Lotus/Types/Gameplay/1999Wf/Dialogue/ArthurDialogue_rom.dialogue", "dialogueConvo": "ArthurBirthdayConvo" }] }, - { - "day": 309, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/Forma" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalBoreal" } - ] - }, - { - "day": 314, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/PowerStrengthAndEfficiencyPerEnergySpent" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/ElectricalDamageOnBulletJump" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/MeleeSlideFowardMomentumOnEnemyHit" } - ] - }, - { "day": 322, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesMedium" }] }, - { - "day": 328, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker" }, - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleSmall" } - ] - }, - { "day": 337, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithAbilitiesHard" }] }, - { "day": 338, "events": [{ "type": "CET_PLOT", "dialogueName": "/Lotus/Types/Gameplay/1999Wf/Dialogue/QuincyDialogue_rom.dialogue", "dialogueConvo": "QuincyBirthdayConvo" }] }, - { - "day": 340, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/MeleeCritChance" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/RadiationProcOnTakeDamage" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/AbilityStrength" } - ] - }, - { - "day": 343, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponPrimaryArcaneUnlocker" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/FormaAura" } - ] - }, - { "day": 352, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillTankHard" }] }, - { - "day": 364, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Boosters/ModDropChanceBooster3DayStoreItem" } - ] - } -] diff --git a/static/fixed_responses/worldState/1999_spring_days.json b/static/fixed_responses/worldState/1999_spring_days.json deleted file mode 100644 index 4386f2a4..00000000 --- a/static/fixed_responses/worldState/1999_spring_days.json +++ /dev/null @@ -1,75 +0,0 @@ -[ - { "day": 100, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesEasy" }] }, - { - "day": 101, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/EnergyOrbToAbilityRange" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/ElectricStatusDamageAndChance" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/EnergyRestoration" } - ] - }, - { - "day": 102, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalBoreal" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack" } - ] - }, - { "day": 106, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesEasy" }] }, - { - "day": 107, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleSmall" } - ] - }, - { "day": 122, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithMeleeMedium" }] }, - { - "day": 127, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/Forma" }, - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Packages/Calendar/CalendarVosforPack" } - ] - }, - { "day": 129, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithAbilitiesMedium" }] }, - { - "day": 135, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponMeleeArcaneUnlocker" } - ] - }, - { - "day": 142, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/BlastEveryXShots" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/MagnitizeWithinRangeEveryXCasts" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/GenerateOmniOrbsOnWeakKill" } - ] - }, - { "day": 143, "events": [{ "type": "CET_PLOT", "dialogueName": "/Lotus/Types/Gameplay/1999Wf/Dialogue/JabirDialogue_rom.dialogue", "dialogueConvo": "AmirBirthdayConvo" }] }, - { "day": 161, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithAbilitiesHard" }] }, - { - "day": 165, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/Forma" }, - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Boosters/ModDropChanceBooster3DayStoreItem" } - ] - }, - { "day": 169, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsHard" }] }, - { - "day": 171, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/GasChanceToPrimaryAndSecondary" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/AbilityStrength" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/MeleeCritChance" } - ] - }, - { - "day": 176, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Recipes/Components/WeaponUtilityUnlockerBlueprint" } - ] - } -] diff --git a/static/fixed_responses/worldState/1999_summer_days.json b/static/fixed_responses/worldState/1999_summer_days.json deleted file mode 100644 index 99beee4a..00000000 --- a/static/fixed_responses/worldState/1999_summer_days.json +++ /dev/null @@ -1,75 +0,0 @@ -[ - { "day": 186, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesEasy" }] }, - { "day": 191, "events": [{ "type": "CET_PLOT", "dialogueName": "/Lotus/Types/Gameplay/1999Wf/Dialogue/AoiDialogue_rom.dialogue", "dialogueConvo": "AoiBirthdayConvo" }] }, - { - "day": 193, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalAmar" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack" } - ] - }, - { - "day": 197, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/MeleeAttackSpeed" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/AbilityStrength" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/CompanionDamage" } - ] - }, - { "day": 199, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithMeleeMedium" }] }, - { - "day": 210, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CircuitSilverSteelPathFusionBundle" } - ] - }, - { "day": 215, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesWithMeleeEasy" }] }, - { - "day": 228, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Recipes/Components/WeaponUtilityUnlockerBlueprint" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarRivenPack" } - ] - }, - { "day": 236, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsMedium" }] }, - { - "day": 237, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleLarge" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack" } - ] - }, - { - "day": 240, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/RadialJavelinOnHeavy" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/SharedFreeAbilityEveryXCasts" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/CompanionsRadiationChance" } - ] - }, - { "day": 245, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithAbilitiesHard" }] }, - { - "day": 250, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Boosters/AffinityBooster3DayStoreItem" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Recipes/Components/OrokinReactorBlueprint" } - ] - }, - { "day": 254, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillTankHard" }] }, - { - "day": 267, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker" } - ] - }, - { - "day": 270, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/EnergyOrbToAbilityRange" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/PunchToPrimary" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/OvershieldCap" } - ] - } -] diff --git a/static/fixed_responses/worldState/1999_winter_days.json b/static/fixed_responses/worldState/1999_winter_days.json deleted file mode 100644 index 700866d3..00000000 --- a/static/fixed_responses/worldState/1999_winter_days.json +++ /dev/null @@ -1,75 +0,0 @@ -[ - { "day": 6, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillEximusEasy" }] }, - { - "day": 15, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/MagazineCapacity" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/Armor" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/EnergyRestoration" } - ] - }, - { "day": 21, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesEasy" }] }, - { - "day": 25, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalGreen" } - ] - }, - { - "day": 31, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Recipes/Components/WeaponUtilityUnlockerBlueprint" }, - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleSmall" } - ] - }, - { "day": 43, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithAbilitiesMedium" }] }, - { "day": 45, "events": [{ "type": "CET_PLOT", "dialogueName": "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue", "dialogueConvo": "LettieBirthdayConvo" }] }, - { - "day": 47, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Boosters/AffinityBooster3DayStoreItem" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack" } - ] - }, - { "day": 48, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithMeleeMedium" }] }, - { - "day": 54, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/CompanionsBuffNearbyPlayer" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/OrbsDuplicateOnPickup" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/FinisherChancePerComboMultiplier" } - ] - }, - { - "day": 56, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleSmall" } - ] - }, - { "day": 71, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesHard" }] }, - { - "day": 77, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CircuitSilverSteelPathFusionBundle" } - ] - }, - { "day": 80, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsMedium" }] }, - { - "day": 83, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Recipes/Components/OrokinReactorBlueprint" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponUtilityUnlocker" } - ] - }, - { - "day": 87, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/EnergyOrbToAbilityRange" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/MeleeAttackSpeed" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/CompanionDamage" } - ] - } -] diff --git a/static/fixed_responses/worldState/worldState.json b/static/fixed_responses/worldState/worldState.json index 3b4143e5..dd76dd56 100644 --- a/static/fixed_responses/worldState/worldState.json +++ b/static/fixed_responses/worldState/worldState.json @@ -2716,90 +2716,5 @@ "ConstructionProjects": [], "TwitchPromos": [], "ExperimentRecommended": [], - "ForceLogoutVersion": 0, - "KnownCalendarSeasons": [ - { - "Activation": { "$date": { "$numberLong": "1733961600000" } }, - "Expiry": { "$date": { "$numberLong": "2000000000000" } }, - "Days": [ - { "day": 6, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillEximusEasy" }] }, - { - "day": 15, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/MagazineCapacity" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/Armor" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/EnergyRestoration" } - ] - }, - { "day": 21, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesEasy" }] }, - { - "day": 25, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Gameplay/NarmerSorties/ArchonCrystalGreen" } - ] - }, - { - "day": 31, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Recipes/Components/WeaponUtilityUnlockerBlueprint" }, - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleSmall" } - ] - }, - { "day": 43, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillEnemiesWithAbilitiesMedium" }] }, - { "day": 45, "events": [{ "type": "CET_PLOT", "dialogueName": "/Lotus/Types/Gameplay/1999Wf/Dialogue/LettieDialogue_rom.dialogue", "dialogueConvo": "LettieBirthdayConvo" }] }, - { - "day": 47, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Boosters/AffinityBooster3DayStoreItem" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarMajorArtifactPack" } - ] - }, - { "day": 48, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillScaldraEnemiesWithMeleeMedium" }] }, - { - "day": 54, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/CompanionsBuffNearbyPlayer" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/OrbsDuplicateOnPickup" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/FinisherChancePerComboMultiplier" } - ] - }, - { - "day": 56, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/BoosterPacks/CalendarArtifactPack" }, - { "type": "CET_REWARD", "reward": "/Lotus/Types/StoreItems/Packages/Calendar/CalendarKuvaBundleSmall" } - ] - }, - { "day": 71, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarKillTechrotEnemiesHard" }] }, - { - "day": 77, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponSecondaryArcaneUnlocker" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Upgrades/Mods/FusionBundles/CircuitSilverSteelPathFusionBundle" } - ] - }, - { "day": 80, "events": [{ "type": "CET_CHALLENGE", "challenge": "/Lotus/Types/Challenges/Calendar1999/CalendarDestroyPropsMedium" }] }, - { - "day": 83, - "events": [ - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Recipes/Components/OrokinReactorBlueprint" }, - { "type": "CET_REWARD", "reward": "/Lotus/StoreItems/Types/Items/MiscItems/WeaponUtilityUnlocker" } - ] - }, - { - "day": 87, - "events": [ - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/EnergyOrbToAbilityRange" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/MeleeAttackSpeed" }, - { "type": "CET_UPGRADE", "upgrade": "/Lotus/Upgrades/Calendar/CompanionDamage" } - ] - } - ], - "Season": "CST_WINTER", - "YearIteration": 0, - "Version": 17, - "UpgradeAvaliabilityRequirements": ["/Lotus/Upgrades/Calendar/1999UpgradeApplicationRequirement"] - } - ] + "ForceLogoutVersion": 0 } From 76a53bb1f61fb176594502a506f2efdab23434c1 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Thu, 17 Apr 2025 08:00:31 -0700 Subject: [PATCH 4/6] fix: don't consider simaris title 1 to earn a free favour (#1690) Fixes #1688 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1690 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/controllers/api/syndicateSacrificeController.ts | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/controllers/api/syndicateSacrificeController.ts b/src/controllers/api/syndicateSacrificeController.ts index 36ad07cb..fd385999 100644 --- a/src/controllers/api/syndicateSacrificeController.ts +++ b/src/controllers/api/syndicateSacrificeController.ts @@ -51,7 +51,7 @@ export const syndicateSacrificeController: RequestHandler = async (request, resp syndicate.Title ??= 0; syndicate.Title += 1; - if (syndicate.Title > 0 && manifest.favours.length != 0) { + if (syndicate.Title > 0 && manifest.favours.find(x => x.rankUpReward && x.requiredLevel == syndicate.Title)) { syndicate.FreeFavorsEarned ??= []; if (!syndicate.FreeFavorsEarned.includes(syndicate.Title)) { syndicate.FreeFavorsEarned.push(syndicate.Title); From 419096f603ee2e97c5aa0afe203cfb64088efba2 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Thu, 17 Apr 2025 08:01:59 -0700 Subject: [PATCH 5/6] feat: noDeathMarks cheat (#1691) Closes #1583 Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1691 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/services/configService.ts | 1 + src/services/missionInventoryUpdateService.ts | 31 ++++++++++--------- static/webui/index.html | 4 +++ 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 + 10 files changed, 29 insertions(+), 14 deletions(-) diff --git a/config.json.example b/config.json.example index 9d072329..32562400 100644 --- a/config.json.example +++ b/config.json.example @@ -33,6 +33,7 @@ "noArgonCrystalDecay": false, "noMasteryRankUpCooldown": false, "noVendorPurchaseLimits": true, + "noDeathMarks": false, "noKimCooldowns": false, "instantResourceExtractorDrones": false, "noResourceExtractorDronesDamage": false, diff --git a/src/services/configService.ts b/src/services/configService.ts index cb1a2c38..24707bd5 100644 --- a/src/services/configService.ts +++ b/src/services/configService.ts @@ -39,6 +39,7 @@ interface IConfig { noArgonCrystalDecay?: boolean; noMasteryRankUpCooldown?: boolean; noVendorPurchaseLimits?: boolean; + noDeathMarks?: boolean; noKimCooldowns?: boolean; instantResourceExtractorDrones?: boolean; noResourceExtractorDronesDamage?: boolean; diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 0b452ccc..c30af726 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -54,6 +54,7 @@ import { getInfNodes } from "@/src/helpers/nemesisHelpers"; import { Loadout } from "../models/inventoryModels/loadoutModel"; import { ILoadoutConfigDatabase } from "../types/saveLoadoutTypes"; import { getWorldState } from "./worldStateService"; +import { config } from "./configService"; const getRotations = (rewardInfo: IRewardInfo, tierOverride?: number): number[] => { // For Spy missions, e.g. 3 vaults cracked = A, B, C @@ -418,22 +419,24 @@ export const addMissionInventoryUpdates = async ( break; } case "DeathMarks": { - for (const bossName of value) { - if (inventory.DeathMarks.indexOf(bossName) == -1) { - // It's a new death mark; we have to say the line. - await createMessage(inventory.accountOwnerId, [ - { - sub: bossName, - sndr: "/Lotus/Language/G1Quests/DeathMarkSender", - msg: "/Lotus/Language/G1Quests/DeathMarkMessage", - icon: "/Lotus/Interface/Icons/Npcs/Stalker_d.png", - highPriority: true, - expiry: new Date(Date.now() + 86400_000) // TOVERIFY: This type of inbox message seems to automatically delete itself. We'll just delete it after 24 hours, but it's clear if this is correct. - } - ]); + if (!config.noDeathMarks) { + for (const bossName of value) { + if (inventory.DeathMarks.indexOf(bossName) == -1) { + // It's a new death mark; we have to say the line. + await createMessage(inventory.accountOwnerId, [ + { + sub: bossName, + sndr: "/Lotus/Language/G1Quests/DeathMarkSender", + msg: "/Lotus/Language/G1Quests/DeathMarkMessage", + icon: "/Lotus/Interface/Icons/Npcs/Stalker_d.png", + highPriority: true, + expiry: new Date(Date.now() + 86400_000) // TOVERIFY: This type of inbox message seems to automatically delete itself. We'll just delete it after 24 hours, but it's clear if this is correct. + } + ]); + } } + inventory.DeathMarks = value; } - inventory.DeathMarks = value; break; } case "CapturedAnimals": { diff --git a/static/webui/index.html b/static/webui/index.html index ec786b4e..3830e378 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -611,6 +611,10 @@ +
+ + +
diff --git a/static/webui/translations/de.js b/static/webui/translations/de.js index 20be9fbd..2357d455 100644 --- a/static/webui/translations/de.js +++ b/static/webui/translations/de.js @@ -138,6 +138,7 @@ dict = { cheats_noArgonCrystalDecay: `Argon-Kristalle verschwinden niemals`, cheats_noMasteryRankUpCooldown: `Keine Wartezeit beim Meisterschaftsrangaufstieg`, cheats_noVendorPurchaseLimits: `Keine Kaufbeschränkungen bei Händlern`, + cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`, cheats_noKimCooldowns: `Keine Wartezeit bei KIM`, cheats_instantResourceExtractorDrones: `Sofortige Ressourcen-Extraktor-Drohnen`, cheats_noResourceExtractorDronesDamage: `Kein Schaden für Ressourcen-Extraktor-Drohnen`, diff --git a/static/webui/translations/en.js b/static/webui/translations/en.js index bbf2561a..3b6fb449 100644 --- a/static/webui/translations/en.js +++ b/static/webui/translations/en.js @@ -137,6 +137,7 @@ dict = { cheats_noArgonCrystalDecay: `No Argon Crystal Decay`, cheats_noMasteryRankUpCooldown: `No Mastery Rank Up Cooldown`, cheats_noVendorPurchaseLimits: `No Vendor Purchase Limits`, + cheats_noDeathMarks: `No Death Marks`, cheats_noKimCooldowns: `No KIM Cooldowns`, cheats_instantResourceExtractorDrones: `Instant Resource Extractor Drones`, cheats_noResourceExtractorDronesDamage: `No Resource Extractor Drones Damage`, diff --git a/static/webui/translations/es.js b/static/webui/translations/es.js index c979bddc..8b751375 100644 --- a/static/webui/translations/es.js +++ b/static/webui/translations/es.js @@ -138,6 +138,7 @@ dict = { cheats_noArgonCrystalDecay: `Sin descomposición de cristal de Argón`, cheats_noMasteryRankUpCooldown: `Sin tiempo de espera para rango de maestría`, cheats_noVendorPurchaseLimits: `Sin límite de compras de vendedores`, + cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`, cheats_noKimCooldowns: `Sin tiempo de espera para conversaciones KIM`, cheats_instantResourceExtractorDrones: `Drones de extracción de recursos instantáneos`, cheats_noResourceExtractorDronesDamage: `Sin daño a los drones extractores de recursos`, diff --git a/static/webui/translations/fr.js b/static/webui/translations/fr.js index 54f041c6..b1938b53 100644 --- a/static/webui/translations/fr.js +++ b/static/webui/translations/fr.js @@ -138,6 +138,7 @@ dict = { cheats_noArgonCrystalDecay: `[UNTRANSLATED] No Argon Crystal Decay`, cheats_noMasteryRankUpCooldown: `[UNTRANSLATED] No Mastery Rank Up Cooldown`, cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`, + cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`, cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`, cheats_instantResourceExtractorDrones: `Ressources de drone d'extraction instantannées`, cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`, diff --git a/static/webui/translations/ru.js b/static/webui/translations/ru.js index 62c82f70..4a5dceeb 100644 --- a/static/webui/translations/ru.js +++ b/static/webui/translations/ru.js @@ -138,6 +138,7 @@ dict = { cheats_noArgonCrystalDecay: `Без распада аргоновых кристаллов`, cheats_noMasteryRankUpCooldown: `Повышение ранга мастерства без кулдауна`, cheats_noVendorPurchaseLimits: `Отсутствие лимитов на покупки у вендоров`, + cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`, cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`, cheats_instantResourceExtractorDrones: `Мгновенные Экстракторы Ресурсов`, cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`, diff --git a/static/webui/translations/zh.js b/static/webui/translations/zh.js index 3d7af8ec..5af41bea 100644 --- a/static/webui/translations/zh.js +++ b/static/webui/translations/zh.js @@ -138,6 +138,7 @@ dict = { cheats_noArgonCrystalDecay: `[UNTRANSLATED] No Argon Crystal Decay`, cheats_noMasteryRankUpCooldown: `[UNTRANSLATED] No Mastery Rank Up Cooldown`, cheats_noVendorPurchaseLimits: `[UNTRANSLATED] No Vendor Purchase Limits`, + cheats_noDeathMarks: `[UNTRANSLATED] No Death Marks`, cheats_noKimCooldowns: `[UNTRANSLATED] No KIM Cooldowns`, cheats_instantResourceExtractorDrones: `即时资源采集无人机`, cheats_noResourceExtractorDronesDamage: `[UNTRANSLATED] No Resource Extractor Drones Damage`, From e38d52fb1bfa5a760ae145309a894dce75181691 Mon Sep 17 00:00:00 2001 From: Sainan <63328889+Sainan@users.noreply.github.com> Date: Thu, 17 Apr 2025 08:02:13 -0700 Subject: [PATCH 6/6] feat: sortie reward (#1692) May work somewhat for lite sorties, didn't test that. They'd also need some extra handling with regards to the archon shards with their dynamic probabilities. Reviewed-on: https://onlyg.it/OpenWF/SpaceNinjaServer/pulls/1692 Co-authored-by: Sainan <63328889+Sainan@users.noreply.github.com> Co-committed-by: Sainan <63328889+Sainan@users.noreply.github.com> --- src/models/inventoryModels/inventoryModel.ts | 29 +++++++++++++++++-- src/services/missionInventoryUpdateService.ts | 14 +++++++++ src/types/inventoryTypes/inventoryTypes.ts | 13 +++++++-- src/types/requestTypes.ts | 3 ++ 4 files changed, 55 insertions(+), 4 deletions(-) diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 97a0022e..dcd59ff7 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -86,7 +86,9 @@ import { IWeeklyMission, ILockedWeaponGroupDatabase, IPersonalTechProjectDatabase, - IPersonalTechProjectClient + IPersonalTechProjectClient, + ILastSortieRewardDatabase, + ILastSortieRewardClient } from "../../types/inventoryTypes/inventoryTypes"; import { IOid } from "../../types/commonTypes"; import { @@ -1202,6 +1204,28 @@ const alignmentSchema = new Schema( { _id: false } ); +const lastSortieRewardSchema = new Schema( + { + SortieId: Schema.Types.ObjectId, + StoreItem: String, + Manifest: String + }, + { _id: false } +); + +lastSortieRewardSchema.set("toJSON", { + virtuals: true, + transform(_doc, obj) { + const db = obj as ILastSortieRewardDatabase; + const client = obj as ILastSortieRewardClient; + + client.SortieId = toOid(db.SortieId); + + delete obj._id; + delete obj.__v; + } +}); + const lockedWeaponGroupSchema = new Schema( { s: Schema.Types.ObjectId, @@ -1419,7 +1443,8 @@ const inventorySchema = new Schema( //https://warframe.fandom.com/wiki/Sortie CompletedSorties: [String], - LastSortieReward: [Schema.Types.Mixed], + LastSortieReward: { type: [lastSortieRewardSchema], default: undefined }, + LastLiteSortieReward: { type: [lastSortieRewardSchema], default: undefined }, // Resource Extractor Drones Drones: [droneSchema], diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index c30af726..3ff26b29 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -584,6 +584,16 @@ export const addMissionRewards = async ( const AffiliationMods: IAffiliationMods[] = []; let SyndicateXPItemReward; + if (rewardInfo.sortieTag == "Final") { + inventory.LastSortieReward = [ + { + SortieId: new Types.ObjectId(rewardInfo.sortieId!.split("_")[1]), + StoreItem: MissionRewards[0].StoreItem, + Manifest: "/Lotus/Types/Game/MissionDecks/SortieRewards" + } + ]; + } + let missionCompletionCredits = 0; //inventory change is what the client has not rewarded itself, also the client needs to know the credit changes for display if (levelKeyName) { @@ -943,6 +953,10 @@ function getLevelCreditRewards(node: IRegion): number { function getRandomMissionDrops(RewardInfo: IRewardInfo, tierOverride: number | undefined): IMissionReward[] { const drops: IMissionReward[] = []; + if (RewardInfo.sortieTag == "Final") { + const drop = getRandomRewardByChance(ExportRewards["/Lotus/Types/Game/MissionDecks/SortieRewards"][0])!; + drops.push({ StoreItem: drop.type, ItemCount: drop.itemCount }); + } if (RewardInfo.periodicMissionTag?.startsWith("HardDaily")) { drops.push({ StoreItem: "/Lotus/StoreItems/Types/Items/MiscItems/SteelEssence", diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index d6e2ab34..ef90dbf5 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -47,6 +47,8 @@ export interface IInventoryDatabase | "BrandedSuits" | "LockedWeaponGroup" | "PersonalTechProjects" + | "LastSortieReward" + | "LastLiteSortieReward" | TEquipmentKey >, InventoryDatabaseEquipment { @@ -79,6 +81,8 @@ export interface IInventoryDatabase BrandedSuits?: Types.ObjectId[]; LockedWeaponGroup?: ILockedWeaponGroupDatabase; PersonalTechProjects: IPersonalTechProjectDatabase[]; + LastSortieReward?: ILastSortieRewardDatabase[]; + LastLiteSortieReward?: ILastSortieRewardDatabase[]; } export interface IQuestKeyDatabase { @@ -277,7 +281,8 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu Wishlist: string[]; Alignment?: IAlignment; CompletedSorties: string[]; - LastSortieReward: ILastSortieReward[]; + LastSortieReward?: ILastSortieRewardClient[]; + LastLiteSortieReward?: ILastSortieRewardClient[]; Drones: IDroneClient[]; StepSequencers: IStepSequencer[]; ActiveAvatarImageType: string; @@ -724,12 +729,16 @@ export enum Status { StatusStasis = "STATUS_STASIS" } -export interface ILastSortieReward { +export interface ILastSortieRewardClient { SortieId: IOid; StoreItem: string; Manifest: string; } +export interface ILastSortieRewardDatabase extends Omit { + SortieId: Types.ObjectId; +} + export interface ILibraryDailyTaskInfo { EnemyTypes: string[]; EnemyLocTag: string; diff --git a/src/types/requestTypes.ts b/src/types/requestTypes.ts index fff164a8..9441f632 100644 --- a/src/types/requestTypes.ts +++ b/src/types/requestTypes.ts @@ -129,6 +129,9 @@ export type IMissionInventoryUpdateRequest = { export interface IRewardInfo { node: string; + sortieId?: string; + sortieTag?: string; + sortiePrereqs?: string[]; VaultsCracked?: number; // for Spy missions rewardTier?: number; nightmareMode?: boolean;