diff --git a/.eslintrc b/.eslintrc index c7994fc1..f5af1b0e 100644 --- a/.eslintrc +++ b/.eslintrc @@ -11,17 +11,17 @@ "node": true }, "rules": { - "@typescript-eslint/explicit-function-return-type": "warn", - "@typescript-eslint/restrict-template-expressions": "warn", - "@typescript-eslint/restrict-plus-operands": "warn", - "@typescript-eslint/no-unsafe-member-access": "warn", + "@typescript-eslint/explicit-function-return-type": "error", + "@typescript-eslint/restrict-template-expressions": "error", + "@typescript-eslint/restrict-plus-operands": "error", + "@typescript-eslint/no-unsafe-member-access": "error", "@typescript-eslint/no-unused-vars": ["error", { "argsIgnorePattern": "^_", "caughtErrors": "none" }], "@typescript-eslint/no-unsafe-argument": "error", - "@typescript-eslint/no-unsafe-call": "warn", - "@typescript-eslint/no-unsafe-assignment": "warn", - "@typescript-eslint/no-explicit-any": "warn", - "no-loss-of-precision": "warn", - "@typescript-eslint/no-unnecessary-condition": "warn", + "@typescript-eslint/no-unsafe-call": "error", + "@typescript-eslint/no-unsafe-assignment": "error", + "@typescript-eslint/no-explicit-any": "error", + "no-loss-of-precision": "error", + "@typescript-eslint/no-unnecessary-condition": "error", "@typescript-eslint/no-base-to-string": "off", "no-case-declarations": "error", "prettier/prettier": "error", diff --git a/src/controllers/api/claimCompletedRecipeController.ts b/src/controllers/api/claimCompletedRecipeController.ts index 071a6c9c..c70a40be 100644 --- a/src/controllers/api/claimCompletedRecipeController.ts +++ b/src/controllers/api/claimCompletedRecipeController.ts @@ -13,7 +13,8 @@ import { addItem, addRecipes, occupySlot, - combineInventoryChanges + combineInventoryChanges, + addKubrowPetPrint } from "@/src/services/inventoryService"; import { IInventoryChanges } from "@/src/types/purchaseTypes"; import { IEquipmentClient } from "@/src/types/inventoryTypes/commonInventoryTypes"; @@ -119,6 +120,9 @@ export const claimCompletedRecipeController: RequestHandler = async (req, res) = } } pet.Details!.Status = canSetActive ? Status.StatusAvailable : Status.StatusStasis; + } else if (recipe.secretIngredientAction == "SIA_DISTILL_PRINT") { + const pet = inventory.KubrowPets.id(pendingRecipe.KubrowPet!)!; + addKubrowPetPrint(inventory, pet, InventoryChanges); } else if (recipe.secretIngredientAction != "SIA_UNBRAND") { InventoryChanges = { ...InventoryChanges, diff --git a/src/controllers/api/startRecipeController.ts b/src/controllers/api/startRecipeController.ts index 8f68fc28..42f138e5 100644 --- a/src/controllers/api/startRecipeController.ts +++ b/src/controllers/api/startRecipeController.ts @@ -45,9 +45,9 @@ export const startRecipeController: RequestHandler = async (req, res) => { for (let i = 0; i != recipe.ingredients.length; ++i) { if (startRecipeRequest.Ids[i] && startRecipeRequest.Ids[i][0] != "/") { if (recipe.ingredients[i].ItemType == "/Lotus/Types/Game/KubrowPet/Eggs/KubrowPetEggItem") { - const index = inventory.KubrowPetEggs!.findIndex(x => x._id.equals(startRecipeRequest.Ids[i])); + const index = inventory.KubrowPetEggs.findIndex(x => x._id.equals(startRecipeRequest.Ids[i])); if (index != -1) { - inventory.KubrowPetEggs!.splice(index, 1); + inventory.KubrowPetEggs.splice(index, 1); } } else { const category = ExportWeapons[recipe.ingredients[i].ItemType].productCategory; @@ -72,6 +72,10 @@ export const startRecipeController: RequestHandler = async (req, res) => { if (recipe.secretIngredientAction == "SIA_CREATE_KUBROW") { inventoryChanges = addKubrowPet(inventory, getRandomElement(recipe.secretIngredients!)!.ItemType); pr.KubrowPet = new Types.ObjectId(fromOid(inventoryChanges.KubrowPets![0].ItemId)); + } else if (recipe.secretIngredientAction == "SIA_DISTILL_PRINT") { + pr.KubrowPet = new Types.ObjectId(startRecipeRequest.Ids[recipe.ingredients.length]); + const pet = inventory.KubrowPets.id(pr.KubrowPet)!; + pet.Details!.PrintsRemaining -= 1; } else if (recipe.secretIngredientAction == "SIA_SPECTRE_LOADOUT_COPY") { const spectreLoadout: ISpectreLoadout = { ItemType: recipe.resultType, diff --git a/src/models/inventoryModels/inventoryModel.ts b/src/models/inventoryModels/inventoryModel.ts index fafdb8b3..57a1e7a3 100644 --- a/src/models/inventoryModels/inventoryModel.ts +++ b/src/models/inventoryModels/inventoryModel.ts @@ -99,7 +99,9 @@ import { ILotusCustomization, IEndlessXpReward, IPersonalGoalProgressDatabase, - IPersonalGoalProgressClient + IPersonalGoalProgressClient, + IKubrowPetPrintClient, + IKubrowPetPrintDatabase } from "../../types/inventoryTypes/inventoryTypes"; import { IOid } from "../../types/commonTypes"; import { @@ -1008,6 +1010,27 @@ const traitsSchema = new Schema( { _id: false } ); +const kubrowPetPrintSchema = new Schema({ + ItemType: String, + Name: String, + IsMale: Boolean, + Size: Number, + DominantTraits: traitsSchema, + RecessiveTraits: traitsSchema +}); +kubrowPetPrintSchema.set("toJSON", { + virtuals: true, + transform(_doc, obj) { + const db = obj as IKubrowPetPrintDatabase; + const client = obj as IKubrowPetPrintClient; + + client.ItemId = toOid(db._id); + + delete obj._id; + delete obj.__v; + } +}); + const detailsSchema = new Schema( { Name: String, @@ -1511,7 +1534,7 @@ const inventorySchema = new Schema( KubrowPetEggs: [kubrowPetEggSchema], //Prints Cat(3 Prints)\Kubrow(2 Prints) Pets - //KubrowPetPrints: [Schema.Types.Mixed], + KubrowPetPrints: [kubrowPetPrintSchema], //Item for EquippedGear example:Scaner,LoadoutTechSummon etc Consumables: [typeCountSchema], @@ -1852,6 +1875,7 @@ export type InventoryDocumentProps = { CrewShipSalvagedWeaponSkins: Types.DocumentArray; PersonalTechProjects: Types.DocumentArray; CrewMembers: Types.DocumentArray; + KubrowPetPrints: Types.DocumentArray; } & { [K in TEquipmentKey]: Types.DocumentArray }; // eslint-disable-next-line @typescript-eslint/no-empty-object-type diff --git a/src/services/inventoryService.ts b/src/services/inventoryService.ts index fafbca6c..d7e2bb88 100644 --- a/src/services/inventoryService.ts +++ b/src/services/inventoryService.ts @@ -29,7 +29,8 @@ import { ICalendarProgress, INemesisWeaponTargetFingerprint, INemesisPetTargetFingerprint, - IDialogueDatabase + IDialogueDatabase, + IKubrowPetPrintClient } from "@/src/types/inventoryTypes/inventoryTypes"; import { IGenericUpdate, IUpdateNodeIntrosResponse } from "../types/genericUpdate"; import { IKeyChainRequest, IMissionInventoryUpdateRequest } from "../types/requestTypes"; @@ -424,7 +425,6 @@ export const addItem = async ( ItemType: "/Lotus/Types/Game/KubrowPet/Eggs/KubrowEgg", _id: new Types.ObjectId() }; - inventory.KubrowPetEggs ??= []; inventory.KubrowPetEggs.push(egg); changes.push({ ItemType: egg.ItemType, @@ -784,7 +784,11 @@ export const addItem = async ( typeName.substr(1).split("/")[3] == "CatbrowPet" || typeName.substr(1).split("/")[3] == "KubrowPet" ) { - if (typeName != "/Lotus/Types/Game/KubrowPet/Eggs/KubrowPetEggItem") { + if ( + typeName != "/Lotus/Types/Game/KubrowPet/Eggs/KubrowPetEggItem" && + typeName != "/Lotus/Types/Game/KubrowPet/BlankTraitPrint" && + typeName != "/Lotus/Types/Game/KubrowPet/ImprintedTraitPrint" + ) { return addKubrowPet(inventory, typeName, undefined, premiumPurchase); } } else if (typeName.startsWith("/Lotus/Types/Game/CrewShip/CrewMember/")) { @@ -1048,8 +1052,13 @@ export const addKubrowPet = ( const configs: IItemConfig[] = applyDefaultUpgrades(inventory, kubrowPet?.defaultUpgrades); if (!details) { - let traits: ITraits; + const isCatbrow = [ + "/Lotus/Types/Game/CatbrowPet/CheshireCatbrowPetPowerSuit", + "/Lotus/Types/Game/CatbrowPet/MirrorCatbrowPetPowerSuit", + "/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit" + ].includes(kubrowPetName); + let traits: ITraits; if (kubrowPetName == "/Lotus/Types/Game/CatbrowPet/VampireCatbrowPetPowerSuit") { traits = { BaseColor: "/Lotus/Types/Game/CatbrowPet/Colors/CatbrowPetColorBaseVampire", @@ -1064,12 +1073,7 @@ export const addKubrowPet = ( 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, @@ -1088,7 +1092,7 @@ export const addKubrowPet = ( Name: "", IsPuppy: !premiumPurchase, HasCollar: true, - PrintsRemaining: 3, + PrintsRemaining: isCatbrow ? 3 : 2, Status: premiumPurchase ? Status.StatusStasis : Status.StatusIncubating, HatchDate: premiumPurchase ? new Date() : new Date(Date.now() + 10 * unixTimesInMs.hour), // On live, this seems to be somewhat randomised so that the pet hatches 9~11 hours after start. IsMale: !!getRandomInt(0, 1), @@ -1112,6 +1116,26 @@ export const addKubrowPet = ( return inventoryChanges; }; +export const addKubrowPetPrint = ( + inventory: TInventoryDatabaseDocument, + pet: IEquipmentDatabase, + inventoryChanges: IInventoryChanges +): void => { + inventoryChanges.KubrowPetPrints ??= []; + inventoryChanges.KubrowPetPrints.push( + inventory.KubrowPetPrints[ + inventory.KubrowPetPrints.push({ + ItemType: "/Lotus/Types/Game/KubrowPet/ImprintedTraitPrint", + Name: pet.Details!.Name, + IsMale: pet.Details!.IsMale, + Size: pet.Details!.Size, + DominantTraits: pet.Details!.DominantTraits, + RecessiveTraits: pet.Details!.RecessiveTraits + }) - 1 + ].toJSON() + ); +}; + export const updateSlots = ( inventory: TInventoryDatabaseDocument, slotName: SlotNames, diff --git a/src/services/missionInventoryUpdateService.ts b/src/services/missionInventoryUpdateService.ts index 340e7ba4..69e165e7 100644 --- a/src/services/missionInventoryUpdateService.ts +++ b/src/services/missionInventoryUpdateService.ts @@ -525,7 +525,6 @@ export const addMissionInventoryUpdates = async ( } case "KubrowPetEggs": { for (const egg of value) { - inventory.KubrowPetEggs ??= []; inventory.KubrowPetEggs.push({ ItemType: egg.ItemType, _id: new Types.ObjectId() diff --git a/src/types/inventoryTypes/inventoryTypes.ts b/src/types/inventoryTypes/inventoryTypes.ts index 3fd6ba68..11d4daff 100644 --- a/src/types/inventoryTypes/inventoryTypes.ts +++ b/src/types/inventoryTypes/inventoryTypes.ts @@ -40,6 +40,7 @@ export interface IInventoryDatabase | "InfestedFoundry" | "DialogueHistory" | "KubrowPetEggs" + | "KubrowPetPrints" | "PendingCoupon" | "Drones" | "RecentVendorPurchases" @@ -79,7 +80,8 @@ export interface IInventoryDatabase KahlLoadOuts: IOperatorConfigDatabase[]; InfestedFoundry?: IInfestedFoundryDatabase; DialogueHistory?: IDialogueHistoryDatabase; - KubrowPetEggs?: IKubrowPetEggDatabase[]; + KubrowPetEggs: IKubrowPetEggDatabase[]; + KubrowPetPrints: IKubrowPetPrintDatabase[]; PendingCoupon?: IPendingCouponDatabase; Drones: IDroneDatabase[]; RecentVendorPurchases?: IRecentVendorPurchaseDatabase[]; @@ -307,7 +309,7 @@ export interface IInventoryClient extends IDailyAffiliations, InventoryClientEqu FocusUpgrades: IFocusUpgrade[]; HasContributedToDojo?: boolean; HWIDProtectEnabled?: boolean; - //KubrowPetPrints: IKubrowPetPrint[]; + KubrowPetPrints: IKubrowPetPrintClient[]; AlignmentReplay?: IAlignment; PersonalGoalProgress?: IPersonalGoalProgressClient[]; ThemeStyle: string; @@ -722,8 +724,8 @@ export interface IKubrowPetEggDatabase { _id: Types.ObjectId; } -export interface IKubrowPetPrint { - ItemType: KubrowPetPrintItemType; +export interface IKubrowPetPrintClient { + ItemType: "/Lotus/Types/Game/KubrowPet/ImprintedTraitPrint"; Name: string; IsMale: boolean; Size: number; // seems to be 0.7 to 1.0 @@ -733,6 +735,10 @@ export interface IKubrowPetPrint { InheritedModularParts?: any[]; } +export interface IKubrowPetPrintDatabase extends Omit { + _id: Types.ObjectId; +} + export interface ITraits { BaseColor: string; SecondaryColor: string; @@ -746,15 +752,11 @@ export interface ITraits { Tail?: string; } -export enum KubrowPetPrintItemType { - LotusTypesGameKubrowPetImprintedTraitPrint = "/Lotus/Types/Game/KubrowPet/ImprintedTraitPrint" -} - export interface IKubrowPetDetailsDatabase { Name?: string; IsPuppy?: boolean; HasCollar: boolean; - PrintsRemaining?: number; + PrintsRemaining: number; Status: Status; HatchDate?: Date; DominantTraits: ITraits; diff --git a/src/types/purchaseTypes.ts b/src/types/purchaseTypes.ts index be26268b..a1f475aa 100644 --- a/src/types/purchaseTypes.ts +++ b/src/types/purchaseTypes.ts @@ -7,7 +7,8 @@ import { ITypeCount, IRecentVendorPurchaseClient, TEquipmentKey, - ICrewMemberClient + ICrewMemberClient, + IKubrowPetPrintClient } from "./inventoryTypes/inventoryTypes"; export enum PurchaseSource { @@ -78,6 +79,7 @@ export type IInventoryChanges = { NewVendorPurchase?: IRecentVendorPurchaseClient; // >= 38.5.0 RecentVendorPurchases?: IRecentVendorPurchaseClient; // < 38.5.0 CrewMembers?: ICrewMemberClient[]; + KubrowPetPrints?: IKubrowPetPrintClient[]; } & Record< Exclude< string,