diff --git a/src/controllers/api/missionInventoryUpdateController.ts b/src/controllers/api/missionInventoryUpdateController.ts index 3eb0762c..ead3b56e 100644 --- a/src/controllers/api/missionInventoryUpdateController.ts +++ b/src/controllers/api/missionInventoryUpdateController.ts @@ -84,7 +84,7 @@ export const missionInventoryUpdateController: RequestHandler = async (req, res) MissionRewards, ...credits, ...inventoryUpdates, - FusionPoints: inventoryChanges?.FusionPoints, + //FusionPoints: inventoryChanges?.FusionPoints, // This in combination with InventoryJson or InventoryChanges seems to just double the number of endo shown, so unsure when this is needed. SyndicateXPItemReward, AffiliationMods }); diff --git a/src/controllers/api/modularWeaponCraftingController.ts b/src/controllers/api/modularWeaponCraftingController.ts index 8819a2a6..0d083371 100644 --- a/src/controllers/api/modularWeaponCraftingController.ts +++ b/src/controllers/api/modularWeaponCraftingController.ts @@ -23,6 +23,7 @@ import { Status } from "@/src/types/inventoryTypes/inventoryTypes"; interface IModularCraftRequest { WeaponType: string; Parts: string[]; + isWebUi?: boolean; } export const modularWeaponCraftingController: RequestHandler = async (req, res) => { @@ -139,33 +140,39 @@ export const modularWeaponCraftingController: RequestHandler = async (req, res) } defaultOverwrites.Configs = applyDefaultUpgrades(inventory, defaultUpgrades); addEquipment(inventory, category, data.WeaponType, data.Parts, inventoryChanges, defaultOverwrites); - combineInventoryChanges(inventoryChanges, occupySlot(inventory, productCategoryToInventoryBin(category)!, false)); + combineInventoryChanges( + inventoryChanges, + occupySlot(inventory, productCategoryToInventoryBin(category)!, !!data.isWebUi) + ); if (defaultUpgrades) { inventoryChanges.RawUpgrades = defaultUpgrades.map(x => ({ ItemType: x.ItemType, ItemCount: 1 })); } // Remove credits & parts const miscItemChanges = []; - for (const part of data.Parts) { - miscItemChanges.push({ - ItemType: part, - ItemCount: -1 - }); + let currencyChanges = {}; + if (!data.isWebUi) { + for (const part of data.Parts) { + miscItemChanges.push({ + ItemType: part, + ItemCount: -1 + }); + } + currencyChanges = updateCurrency( + inventory, + category == "Hoverboards" || + category == "MoaPets" || + category == "LongGuns" || + category == "Pistols" || + category == "KubrowPets" + ? 5000 + : 4000, // Definitely correct for Melee & OperatorAmps + false + ); + addMiscItems(inventory, miscItemChanges); } - const currencyChanges = updateCurrency( - inventory, - category == "Hoverboards" || - category == "MoaPets" || - category == "LongGuns" || - category == "Pistols" || - category == "KubrowPets" - ? 5000 - : 4000, // Definitely correct for Melee & OperatorAmps - false - ); - addMiscItems(inventory, miscItemChanges); - await inventory.save(); + await inventory.save(); // Tell client what we did res.json({ InventoryChanges: { diff --git a/src/controllers/api/releasePetController.ts b/src/controllers/api/releasePetController.ts index 10625778..5e1d792b 100644 --- a/src/controllers/api/releasePetController.ts +++ b/src/controllers/api/releasePetController.ts @@ -8,7 +8,11 @@ export const releasePetController: RequestHandler = async (req, res) => { const inventory = await getInventory(accountId, "RegularCredits KubrowPets"); const payload = getJSONfromString(String(req.body)); - const inventoryChanges = updateCurrency(inventory, 25000, false); + const inventoryChanges = updateCurrency( + inventory, + payload.recipeName == "/Lotus/Types/Game/KubrowPet/ReleasePetRecipe" ? 25000 : 0, + false + ); inventoryChanges.RemovedIdItems = [{ ItemId: { $oid: payload.petId } }]; inventory.KubrowPets.pull({ _id: payload.petId }); @@ -18,6 +22,6 @@ export const releasePetController: RequestHandler = async (req, res) => { }; interface IReleasePetRequest { - recipeName: "/Lotus/Types/Game/KubrowPet/ReleasePetRecipe"; + recipeName: "/Lotus/Types/Game/KubrowPet/ReleasePetRecipe" | "webui"; petId: string; } diff --git a/src/controllers/api/setHubNpcCustomizationsController.ts b/src/controllers/api/setHubNpcCustomizationsController.ts new file mode 100644 index 00000000..6e199933 --- /dev/null +++ b/src/controllers/api/setHubNpcCustomizationsController.ts @@ -0,0 +1,21 @@ +import { getJSONfromString } from "@/src/helpers/stringHelpers"; +import { getInventory } from "@/src/services/inventoryService"; +import { getAccountIdForRequest } from "@/src/services/loginService"; +import { IHubNpcCustomization } from "@/src/types/inventoryTypes/inventoryTypes"; +import { RequestHandler } from "express"; + +export const setHubNpcCustomizationsController: RequestHandler = async (req, res) => { + const accountId = await getAccountIdForRequest(req); + const inventory = await getInventory(accountId, "HubNpcCustomizations"); + const upload = getJSONfromString(String(req.body)); + inventory.HubNpcCustomizations ??= []; + const cust = inventory.HubNpcCustomizations.find(x => x.Tag == upload.Tag); + if (cust) { + cust.Colors = upload.Colors; + cust.Pattern = upload.Pattern; + } else { + inventory.HubNpcCustomizations.push(upload); + } + await inventory.save(); + res.end(); +}; diff --git a/src/controllers/custom/addModularEquipmentController.ts b/src/controllers/custom/addModularEquipmentController.ts deleted file mode 100644 index 984acd75..00000000 --- a/src/controllers/custom/addModularEquipmentController.ts +++ /dev/null @@ -1,98 +0,0 @@ -import { getAccountIdForRequest } from "@/src/services/loginService"; -import { - getInventory, - addEquipment, - occupySlot, - productCategoryToInventoryBin, - applyDefaultUpgrades -} from "@/src/services/inventoryService"; -import { modularWeaponTypes } from "@/src/helpers/modularWeaponHelper"; -import { getDefaultUpgrades } from "@/src/services/itemDataService"; -import { IEquipmentDatabase } from "@/src/types/inventoryTypes/commonInventoryTypes"; -import { ExportWeapons } from "warframe-public-export-plus"; -import { RequestHandler } from "express"; - -export const addModularEquipmentController: RequestHandler = async (req, res) => { - const requiredFields = new Set(); - const accountId = await getAccountIdForRequest(req); - const request = req.body as IAddModularEquipmentRequest; - const category = modularWeaponTypes[request.ItemType]; - const inventoryBin = productCategoryToInventoryBin(category)!; - requiredFields.add(category); - requiredFields.add(inventoryBin); - - request.ModularParts.forEach(part => { - if (ExportWeapons[part].gunType) { - if (category == "LongGuns") { - request.ItemType = { - GT_RIFLE: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimary", - GT_SHOTGUN: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryShotgun", - GT_BEAM: "/Lotus/Weapons/SolarisUnited/Primary/LotusModularPrimaryBeam" - }[ExportWeapons[part].gunType]; - } else { - request.ItemType = { - GT_RIFLE: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondary", - GT_SHOTGUN: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryShotgun", - GT_BEAM: "/Lotus/Weapons/SolarisUnited/Secondary/LotusModularSecondaryBeam" - }[ExportWeapons[part].gunType]; - } - } else if (request.ItemType == "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetPowerSuit") { - if (part.includes("ZanukaPetPartHead")) { - request.ItemType = { - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadA": - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetAPowerSuit", - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadB": - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetBPowerSuit", - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetParts/ZanukaPetPartHeadC": - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetCPowerSuit" - }[part]!; - } - } - }); - const defaultUpgrades = getDefaultUpgrades(request.ModularParts); - if (defaultUpgrades) { - requiredFields.add("RawUpgrades"); - } - const defaultWeaponsMap: Record = { - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetAPowerSuit": [ - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetMeleeWeaponIP" - ], - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetBPowerSuit": [ - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetMeleeWeaponIS" - ], - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetCPowerSuit": [ - "/Lotus/Types/Friendly/Pets/ZanukaPets/ZanukaPetMeleeWeaponPS" - ] - }; - const defaultWeapons = defaultWeaponsMap[request.ItemType] as string[] | undefined; - if (defaultWeapons) { - for (const defaultWeapon of defaultWeapons) { - const category = ExportWeapons[defaultWeapon].productCategory; - requiredFields.add(category); - requiredFields.add(productCategoryToInventoryBin(category)); - } - } - - const inventory = await getInventory(accountId, Array.from(requiredFields).join(" ")); - if (defaultWeapons) { - for (const defaultWeapon of defaultWeapons) { - const category = ExportWeapons[defaultWeapon].productCategory; - addEquipment(inventory, category, defaultWeapon); - occupySlot(inventory, productCategoryToInventoryBin(category)!, true); - } - } - - const defaultOverwrites: Partial = { - Configs: applyDefaultUpgrades(inventory, defaultUpgrades) - }; - - addEquipment(inventory, category, request.ItemType, request.ModularParts, undefined, defaultOverwrites); - occupySlot(inventory, inventoryBin, true); - await inventory.save(); - res.end(); -}; - -interface IAddModularEquipmentRequest { - ItemType: string; - ModularParts: string[]; -} diff --git a/src/controllers/custom/getItemListsController.ts b/src/controllers/custom/getItemListsController.ts index 38e42bdb..214c51e7 100644 --- a/src/controllers/custom/getItemListsController.ts +++ b/src/controllers/custom/getItemListsController.ts @@ -56,6 +56,7 @@ const getItemListsController: RequestHandler = (req, response) => { res.Syndicates = []; res.OperatorAmps = []; res.QuestKeys = []; + res.KubrowPets = []; for (const [uniqueName, item] of Object.entries(ExportWarframes)) { res[item.productCategory].push({ uniqueName, @@ -64,7 +65,7 @@ const getItemListsController: RequestHandler = (req, response) => { }); } for (const [uniqueName, item] of Object.entries(ExportSentinels)) { - if (item.productCategory == "Sentinels") { + if (item.productCategory != "SpecialItems") { res[item.productCategory].push({ uniqueName, name: getString(item.name, lang) @@ -73,11 +74,13 @@ const getItemListsController: RequestHandler = (req, response) => { } for (const [uniqueName, item] of Object.entries(ExportWeapons)) { if (item.partType) { - res.ModularParts.push({ - uniqueName, - name: getString(item.name, lang), - partType: item.partType - }); + if (!uniqueName.startsWith("/Lotus/Types/Items/Deimos/")) { + res.ModularParts.push({ + uniqueName, + name: getString(item.name, lang), + partType: item.partType + }); + } if (uniqueName.split("/")[5] != "SentTrainingAmplifier") { res.miscitems.push({ uniqueName: uniqueName, diff --git a/src/controllers/custom/manageQuestsController.ts b/src/controllers/custom/manageQuestsController.ts index 04650a06..b951c754 100644 --- a/src/controllers/custom/manageQuestsController.ts +++ b/src/controllers/custom/manageQuestsController.ts @@ -35,10 +35,8 @@ export const manageQuestsController: RequestHandler = async (req, res) => { switch (operation) { case "completeAll": { - if (allQuestKeys.includes(questItemType)) { - for (const questKey of inventory.QuestKeys) { - await completeQuest(inventory, questKey.ItemType); - } + for (const questKey of inventory.QuestKeys) { + await completeQuest(inventory, questKey.ItemType); } break; } diff --git a/src/helpers/inventoryHelpers.ts b/src/helpers/inventoryHelpers.ts index d7fa7b25..79466fb3 100644 --- a/src/helpers/inventoryHelpers.ts +++ b/src/helpers/inventoryHelpers.ts @@ -1,5 +1,6 @@ import { IMongoDate, IOid } from "@/src/types/commonTypes"; import { Types } from "mongoose"; +import { TRarity } from "warframe-public-export-plus"; export const toOid = (objectId: Types.ObjectId): IOid => { return { $oid: objectId.toString() } satisfies IOid; @@ -8,3 +9,144 @@ export const toOid = (objectId: Types.ObjectId): IOid => { export const toMongoDate = (date: Date): IMongoDate => { return { $date: { $numberLong: date.getTime().toString() } }; }; + +export const kubrowWeights: Record = { + COMMON: 6, + UNCOMMON: 4, + RARE: 2, + LEGENDARY: 1 +}; + +export const kubrowFurPatternsWeights: Record = { + COMMON: 6, + UNCOMMON: 5, + RARE: 2, + LEGENDARY: 1 +}; + +export const catbrowDetails = { + Colors: [ + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseA", rarity: "COMMON" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseB", rarity: "COMMON" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseC", rarity: "COMMON" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseD", rarity: "COMMON" as TRarity }, + + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryA", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryB", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryC", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryD", rarity: "UNCOMMON" as TRarity }, + + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryA", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryB", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryC", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryD", rarity: "RARE" as TRarity }, + + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsA", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsB", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsC", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsD", rarity: "LEGENDARY" as TRarity } + ], + + EyeColors: [ + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesA", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesB", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesC", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesD", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesE", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesF", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesG", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesH", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesI", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesJ", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesK", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesL", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesM", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorEyesN", rarity: "LEGENDARY" as TRarity } + ], + + FurPatterns: [{ type: "/Lotus/Types/Game/CatbrowPet/Patterns/CatbrowPetPatternA", rarity: "COMMON" as TRarity }], + + BodyTypes: [ + { type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetRegularBodyType", rarity: "LEGENDARY" as TRarity } + ], + + Heads: [ + { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadA", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadB", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadC", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadD", rarity: "LEGENDARY" as TRarity } + ], + + Tails: [ + { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailA", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailB", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailC", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailD", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailE", rarity: "LEGENDARY" as TRarity } + ] +}; + +export const kubrowDetails = { + Colors: [ + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneA", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneB", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneC", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneD", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneE", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneF", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneG", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMundaneH", rarity: "UNCOMMON" as TRarity }, + + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidA", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidB", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidC", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidD", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidE", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidF", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidG", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorMidH", rarity: "RARE" as TRarity }, + + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantA", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantB", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantC", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantD", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantE", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantF", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantG", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorVibrantH", rarity: "LEGENDARY" as TRarity } + ], + + EyeColors: [ + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesA", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesB", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesC", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesD", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesE", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesF", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesG", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesH", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Colors/KubrowPetColorEyesI", rarity: "LEGENDARY" as TRarity } + ], + + FurPatterns: [ + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternB", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternA", rarity: "UNCOMMON" as TRarity }, + + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternC", rarity: "RARE" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternD", rarity: "RARE" as TRarity }, + + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternE", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/Patterns/KubrowPetPatternF", rarity: "LEGENDARY" as TRarity } + ], + + BodyTypes: [ + { type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetRegularBodyType", rarity: "UNCOMMON" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetHeavyBodyType", rarity: "LEGENDARY" as TRarity }, + { type: "/Lotus/Types/Game/KubrowPet/BodyTypes/KubrowPetThinBodyType", rarity: "LEGENDARY" as TRarity } + ], + + Heads: [], + + Tails: [] +}; diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index 029bf6c0..775de04a 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -95,7 +95,8 @@ import { ISortieRewardAttenuation, IInvasionProgressDatabase, IInvasionProgressClient, - IAccolades + IAccolades, + IHubNpcCustomization } from "../../types/inventoryTypes/inventoryTypes"; import { IOid } from "../../types/commonTypes"; import { @@ -1327,6 +1328,15 @@ const lockedWeaponGroupSchema = new Schema( { _id: false } ); +const hubNpcCustomizationSchema = new Schema( + { + Colors: colorSchema, + Pattern: String, + Tag: String + }, + { _id: false } +); + const inventorySchema = new Schema( { accountOwnerId: Schema.Types.ObjectId, @@ -1680,7 +1690,9 @@ const inventorySchema = new Schema( // G3 + Zanuka BrandedSuits: { type: [Schema.Types.ObjectId], default: undefined }, - LockedWeaponGroup: { type: lockedWeaponGroupSchema, default: undefined } + LockedWeaponGroup: { type: lockedWeaponGroupSchema, default: undefined }, + + HubNpcCustomizations: { type: [hubNpcCustomizationSchema], default: undefined } }, { timestamps: { createdAt: "Created", updatedAt: false } } ); diff --git a/src/routes/api.ts b/src/routes/api.ts index e6416f7a..c3dc2e50 100644 --- a/src/routes/api.ts +++ b/src/routes/api.ts @@ -117,6 +117,7 @@ import { setDojoComponentMessageController } from "@/src/controllers/api/setDojo import { setDojoComponentSettingsController } from "@/src/controllers/api/setDojoComponentSettingsController"; import { setEquippedInstrumentController } from "@/src/controllers/api/setEquippedInstrumentController"; import { setGuildMotdController } from "@/src/controllers/api/setGuildMotdController"; +import { setHubNpcCustomizationsController } from "@/src/controllers/api/setHubNpcCustomizationsController"; import { setPlacedDecoInfoController } from "@/src/controllers/api/setPlacedDecoInfoController"; import { setShipCustomizationsController } from "@/src/controllers/api/setShipCustomizationsController"; import { setShipFavouriteLoadoutController } from "@/src/controllers/api/setShipFavouriteLoadoutController"; @@ -285,6 +286,7 @@ apiRouter.post("/setDojoComponentMessage.php", setDojoComponentMessageController apiRouter.post("/setDojoComponentSettings.php", setDojoComponentSettingsController); apiRouter.post("/setEquippedInstrument.php", setEquippedInstrumentController); apiRouter.post("/setGuildMotd.php", setGuildMotdController); +apiRouter.post("/setHubNpcCustomizations.php", setHubNpcCustomizationsController); apiRouter.post("/setPlacedDecoInfo.php", setPlacedDecoInfoController); apiRouter.post("/setShipCustomizations.php", setShipCustomizationsController); apiRouter.post("/setShipFavouriteLoadout.php", setShipFavouriteLoadoutController); diff --git a/src/routes/custom.ts b/src/routes/custom.ts index 16359226..fbd859c1 100644 --- a/src/routes/custom.ts +++ b/src/routes/custom.ts @@ -15,7 +15,6 @@ import { createAccountController } from "@/src/controllers/custom/createAccountC import { createMessageController } from "@/src/controllers/custom/createMessageController"; import { addCurrencyController } from "@/src/controllers/custom/addCurrencyController"; import { addItemsController } from "@/src/controllers/custom/addItemsController"; -import { addModularEquipmentController } from "@/src/controllers/custom/addModularEquipmentController"; import { addXpController } from "@/src/controllers/custom/addXpController"; import { importController } from "@/src/controllers/custom/importController"; @@ -40,7 +39,6 @@ customRouter.post("/createAccount", createAccountController); customRouter.post("/createMessage", createMessageController); customRouter.post("/addCurrency", addCurrencyController); customRouter.post("/addItems", addItemsController); -customRouter.post("/addModularEquipment", addModularEquipmentController); customRouter.post("/addXp", addXpController); customRouter.post("/import", importController); customRouter.post("/manageQuests", manageQuestsController); diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index 7537c8d6..fd6a597b 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -23,7 +23,10 @@ import { IUpgradeClient, TPartialStartingGear, ILoreFragmentScan, - ICrewMemberClient + ICrewMemberClient, + Status, + IKubrowPetDetailsDatabase, + ITraits } from "@/src/types/inventoryTypes/inventoryTypes"; import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate"; import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes"; @@ -58,14 +61,21 @@ import { ExportWeapons, IDefaultUpgrade, IPowersuit, + ISentinel, TStandingLimitBin } from "warframe-public-export-plus"; import { createShip } from "./shipService"; -import { toOid } from "../helpers/inventoryHelpers"; +import { + catbrowDetails, + kubrowDetails, + kubrowFurPatternsWeights, + kubrowWeights, + toOid +} from "../helpers/inventoryHelpers"; import { addQuestKey, completeQuest } from "@/src/services/questService"; import { handleBundleAcqusition } from "./purchaseService"; import libraryDailyTasks from "@/static/fixed_responses/libraryDailyTasks.json"; -import { getRandomElement, getRandomInt, SRng } from "./rngService"; +import { getRandomElement, getRandomInt, getRandomWeightedReward, SRng } from "./rngService"; import { createMessage } from "./inboxService"; import { getMaxStanding } from "@/src/helpers/syndicateStandingHelper"; @@ -714,6 +724,11 @@ export const addItem = async ( return { MiscItems: miscItemChanges }; + } else if ( + typeName.substr(1).split("/")[3] == "CatbrowPet" || + typeName.substr(1).split("/")[3] == "KubrowPet" + ) { + return addKubrowPet(inventory, typeName, undefined, premiumPurchase); } else if (typeName.startsWith("/Lotus/Types/Game/CrewShip/CrewMember/")) { if (!seed) { throw new Error(`Expected crew member to have a seed`); @@ -932,6 +947,89 @@ export const addSpaceSuit = ( return inventoryChanges; }; +export const addKubrowPet = ( + inventory: TInventoryDatabaseDocument, + kubrowPetName: string, + details: IKubrowPetDetailsDatabase | undefined, + premiumPurchase: boolean, + inventoryChanges: IInventoryChanges = {} +): IInventoryChanges => { + combineInventoryChanges(inventoryChanges, occupySlot(inventory, InventorySlot.SENTINELS, premiumPurchase)); + + const kubrowPet = ExportSentinels[kubrowPetName] as ISentinel | undefined; + const exalted = kubrowPet?.exalted ?? []; + for (const specialItem of exalted) { + addSpecialItem(inventory, specialItem, inventoryChanges); + } + + // eslint-disable-next-line @typescript-eslint/no-unnecessary-condition + const configs: IItemConfig[] = applyDefaultUpgrades(inventory, kubrowPet?.defaultUpgrades); + + if (!details) { + let traits: ITraits; + + if (kubrowPetName == "/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit") { + traits = { + BaseColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseVampire", + SecondaryColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorSecondaryVampire", + TertiaryColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorTertiaryVampire", + AccentColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorAccentsVampire", + EyeColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseA", + FurPattern: "/Lotus/Types/Game/CatbrowPet/Patterns/CatbrowPetPatternVampire", + Personality: kubrowPetName, + BodyType: "/Lotus/Types/Game/CatbrowPet/BodyTypes/CatbrowPetVampireBodyType", + Head: "/Lotus/Types/Game/CatbrowPet/Heads/CatbrowHeadVampire", + Tail: "/Lotus/Types/Game/CatbrowPet/Tails/CatbrowTailVampire" + }; + } else { + const isCatbrow = [ + "/Lotus/Types/Game/CatbrowPet/MirrorCatbrowPetPowerSuit", + "/Lotus/Types/Game/CatbrowPet/CheshireCatbrowPetPowerSuit" + ].includes(kubrowPetName); + const traitsPool = isCatbrow ? catbrowDetails : kubrowDetails; + + traits = { + BaseColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, + SecondaryColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, + TertiaryColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, + AccentColor: getRandomWeightedReward(traitsPool.Colors, kubrowWeights)!.type, + EyeColor: getRandomWeightedReward(traitsPool.EyeColors, kubrowWeights)!.type, + FurPattern: getRandomWeightedReward(traitsPool.FurPatterns, kubrowFurPatternsWeights)!.type, + Personality: kubrowPetName, + BodyType: getRandomWeightedReward(traitsPool.BodyTypes, kubrowWeights)!.type, + Head: isCatbrow ? getRandomWeightedReward(traitsPool.Heads, kubrowWeights)!.type : undefined, + Tail: isCatbrow ? getRandomWeightedReward(traitsPool.Tails, kubrowWeights)!.type : undefined + }; + } + + details = { + Name: "", + IsPuppy: false, + HasCollar: true, + PrintsRemaining: 2, + Status: Status.StatusStasis, + HatchDate: new Date(Math.trunc(Date.now() / 86400000) * 86400000), + IsMale: !!getRandomInt(0, 1), + Size: getRandomInt(70, 100) / 100, + DominantTraits: traits, + RecessiveTraits: traits + }; + } + + const kubrowPetIndex = + inventory.KubrowPets.push({ + ItemType: kubrowPetName, + Configs: configs, + XP: 0, + Details: details, + IsNew: true + }) - 1; + inventoryChanges.KubrowPets ??= []; + inventoryChanges.KubrowPets.push(inventory.KubrowPets[kubrowPetIndex].toJSON()); + + return inventoryChanges; +}; + export const updateSlots = ( inventory: TInventoryDatabaseDocument, slotName: SlotNames, diff --git a/src/services/questService.ts b/src/services/questService.ts index d5ac28dc..053f6eb4 100644 --- a/src/services/questService.ts +++ b/src/services/questService.ts @@ -191,6 +191,25 @@ const getQuestCompletionItems = (questKey: string): ITypeCount[] | undefined => return items; }; +// Checks that `questKey` is in `requirements`, and if so, that all other quests in `requirements` are also already completed. +const doesQuestCompletionFinishSet = ( + inventory: TInventoryDatabaseDocument, + questKey: string, + requirements: string[] +): boolean => { + let holds = false; + for (const requirement of requirements) { + if (questKey == requirement) { + holds = true; + } else { + if (!inventory.QuestKeys.find(x => x.ItemType == requirement)?.Completed) { + return false; + } + } + } + return holds; +}; + const handleQuestCompletion = async ( inventory: TInventoryDatabaseDocument, questKey: string, @@ -218,12 +237,10 @@ const handleQuestCompletion = async ( // Whispers in the Walls is unlocked once The New + Heart of Deimos are completed. if ( - (questKey == "/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain" && - inventory.QuestKeys.find( - x => x.ItemType == "/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain" - )?.Completed) || - (questKey == "/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain" && - inventory.QuestKeys.find(x => x.ItemType == "/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain")?.Completed) + doesQuestCompletionFinishSet(inventory, questKey, [ + "/Lotus/Types/Keys/NewWarQuest/NewWarQuestKeyChain", + "/Lotus/Types/Keys/InfestedMicroplanetQuest/InfestedMicroplanetQuestKeyChain" + ]) ) { await createMessage(inventory.accountOwnerId, [ { @@ -237,6 +254,25 @@ const handleQuestCompletion = async ( ]); } + // The Hex (Quest) is unlocked once The Lotus Eaters + The Duviri Paradox are completed. + if ( + doesQuestCompletionFinishSet(inventory, questKey, [ + "/Lotus/Types/Keys/1999PrologueQuest/1999PrologueQuestKeyChain", + "/Lotus/Types/Keys/DuviriQuest/DuviriQuestKeyChain" + ]) + ) { + await createMessage(inventory.accountOwnerId, [ + { + sndr: "/Lotus/Language/NewWar/P3M1ChooseMara", + msg: "/Lotus/Language/1999Quest/1999QuestInboxBody", + att: ["/Lotus/Types/Keys/1999Quest/1999QuestKeyChain"], + sub: "/Lotus/Language/1999Quest/1999QuestInboxSubject", + icon: "/Lotus/Interface/Icons/Npcs/Operator.png", + highPriority: true + } + ]); + } + const questCompletionItems = getQuestCompletionItems(questKey); logger.debug(`quest completion items`, questCompletionItems); if (questCompletionItems) { diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index b4dbc57c..219f43a5 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -368,6 +368,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu EchoesHexConquestActiveStickers?: string[]; BrandedSuits?: IOid[]; LockedWeaponGroup?: ILockedWeaponGroupClient; + HubNpcCustomizations?: IHubNpcCustomization[]; } export interface IAffiliation { @@ -1228,3 +1229,9 @@ export interface ILockedWeaponGroupDatabase { } export type TPartialStartingGear = Pick; + +export interface IHubNpcCustomization { + Colors?: IColor; + Pattern: string; + Tag: string; +} diff --git a/src/types/purchaseTypes.ts b/src/types/purchaseTypes.ts index eac812a2..3600e6b7 100644 --- a/src/types/purchaseTypes.ts +++ b/src/types/purchaseTypes.ts @@ -39,6 +39,7 @@ export type IInventoryChanges = { RegularCredits?: number; PremiumCredits?: number; PremiumCreditsFree?: number; + FusionPoints?: number; PrimeTokens?: number; InfestedFoundry?: IInfestedFoundryClient; Drones?: IDroneClient[]; diff --git a/static/fixed_responses/questCompletionRewards.json b/static/fixed_responses/questCompletionRewards.json index 71fb423e..1e584e72 100644 --- a/static/fixed_responses/questCompletionRewards.json +++ b/static/fixed_responses/questCompletionRewards.json @@ -11,5 +11,11 @@ "ItemType": "/Lotus/Types/Keys/RailJackBuildQuest/RailjackBuildQuestEmailItem", "ItemCount": 1 } + ], + "/Lotus/Types/Keys/EntratiLab/EntratiQuestKeyChain": [ + { + "ItemType": "/Lotus/Types/Keys/1999PrologueQuest/1999PrologueQuestKeyChain", + "ItemCount": 1 + } ] } diff --git a/static/webui/index.html b/static/webui/index.html index 3830e378..5df7ba59 100644 --- a/static/webui/index.html +++ b/static/webui/index.html @@ -305,7 +305,7 @@ -