From ca7958afedc4920ab16c0d6331d28d58d3b0ec10 Mon Sep 17 00:00:00 2001 From: Dev Date: Fri, 29 Dec 2023 20:22:50 +0000 Subject: [PATCH] Implement `Place of face` hideout area Implement adding/removing favorite items --- project/src/callbacks/InventoryCallbacks.ts | 8 +++ .../src/controllers/InventoryController.ts | 27 ++++++++ project/src/models/enums/HideoutAreas.ts | 5 +- project/src/models/enums/ItemEventActions.ts | 3 +- .../item_events/InventoryItemEventRouter.ts | 3 + project/src/services/ProfileFixerService.ts | 65 +++++++++++++++++++ 6 files changed, 107 insertions(+), 4 deletions(-) diff --git a/project/src/callbacks/InventoryCallbacks.ts b/project/src/callbacks/InventoryCallbacks.ts index c047fc2d..0bb1ef61 100644 --- a/project/src/callbacks/InventoryCallbacks.ts +++ b/project/src/callbacks/InventoryCallbacks.ts @@ -20,6 +20,7 @@ import { IInventoryToggleRequestData } from "@spt-aki/models/eft/inventory/IInve import { IInventoryTransferRequestData } from "@spt-aki/models/eft/inventory/IInventoryTransferRequestData"; import { IOpenRandomLootContainerRequestData } from "@spt-aki/models/eft/inventory/IOpenRandomLootContainerRequestData"; import { IRedeemProfileRequestData } from "@spt-aki/models/eft/inventory/IRedeemProfileRequestData"; +import { ISetFavoriteItems } from "@spt-aki/models/eft/inventory/ISetFavoriteItems"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; @injectable() @@ -165,4 +166,11 @@ export class InventoryCallbacks { return this.inventoryController.redeemProfileReward(pmcData, body, sessionId) } + + public setFavoriteItem(pmcData: IPmcData, + body: ISetFavoriteItems, + sessionId: string): IItemEventRouterResponse + { + return this.inventoryController.setFavoriteItem(pmcData, body, sessionId); + } } diff --git a/project/src/controllers/InventoryController.ts b/project/src/controllers/InventoryController.ts index 4894147e..2109cca7 100644 --- a/project/src/controllers/InventoryController.ts +++ b/project/src/controllers/InventoryController.ts @@ -28,6 +28,7 @@ import { IInventoryToggleRequestData } from "@spt-aki/models/eft/inventory/IInve import { IInventoryTransferRequestData } from "@spt-aki/models/eft/inventory/IInventoryTransferRequestData"; import { IOpenRandomLootContainerRequestData } from "@spt-aki/models/eft/inventory/IOpenRandomLootContainerRequestData"; import { IRedeemProfileRequestData } from "@spt-aki/models/eft/inventory/IRedeemProfileRequestData"; +import { ISetFavoriteItems } from "@spt-aki/models/eft/inventory/ISetFavoriteItems"; import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse"; import { BackendErrorCodes } from "@spt-aki/models/enums/BackendErrorCodes"; import { SkillTypes } from "@spt-aki/models/enums/SkillTypes"; @@ -987,4 +988,30 @@ export class InventoryController return output; } + + public setFavoriteItem(pmcData: IPmcData, request: ISetFavoriteItems, sessionId: string): IItemEventRouterResponse + { + const output = this.eventOutputHolder.getOutput(sessionId); + + if (!pmcData.Inventory.favoriteItems) + { + pmcData.Inventory.favoriteItems = []; + } + + for (const itemId of request.items) + { + // If id already exists in array, we're removing it + const indexOfItemAlreadyFavorited = pmcData.Inventory.favoriteItems.findIndex(x => x === itemId); + if (indexOfItemAlreadyFavorited > -1) + { + pmcData.Inventory.favoriteItems.splice(indexOfItemAlreadyFavorited, 1); + } + else + { + pmcData.Inventory.favoriteItems.push(itemId); + } + } + + return output; + } } diff --git a/project/src/models/enums/HideoutAreas.ts b/project/src/models/enums/HideoutAreas.ts index ba46a3cf..61e1a3fd 100644 --- a/project/src/models/enums/HideoutAreas.ts +++ b/project/src/models/enums/HideoutAreas.ts @@ -1,5 +1,4 @@ -export enum HideoutAreas -{ +export enum HideoutAreas { NOTSET = -1, VENTS = 0, SECURITY = 1, @@ -26,5 +25,5 @@ export enum HideoutAreas EMERGENCY_WALL = 22, GYM = 23, WEAPON_STAND = 24, - WEAPON_STAND_SECONDARY = 25, + WEAPON_STAND_SECONDARY = 25 } diff --git a/project/src/models/enums/ItemEventActions.ts b/project/src/models/enums/ItemEventActions.ts index 0db4c02c..79587fad 100644 --- a/project/src/models/enums/ItemEventActions.ts +++ b/project/src/models/enums/ItemEventActions.ts @@ -23,5 +23,6 @@ export enum ItemEventActions { REMOVE_BUILD = "RemoveBuild", SAVE_EQUIPMENT_BUILD = "SaveEquipmentBuild", REMOVE_EQUIPMENT_BUILD = "RemoveEquipmentBuild", - REDEEM_PROFILE_REWARD = "RedeemProfileReward" + REDEEM_PROFILE_REWARD = "RedeemProfileReward", + SET_FAVORITE_ITEMS = "SetFavoriteItems" } diff --git a/project/src/routers/item_events/InventoryItemEventRouter.ts b/project/src/routers/item_events/InventoryItemEventRouter.ts index 18bbe347..7c2a986c 100644 --- a/project/src/routers/item_events/InventoryItemEventRouter.ts +++ b/project/src/routers/item_events/InventoryItemEventRouter.ts @@ -41,6 +41,7 @@ export class InventoryItemEventRouter extends ItemEventRouterDefinition new HandledRoute(ItemEventActions.OPEN_RANDOM_LOOT_CONTAINER, false), new HandledRoute(ItemEventActions.HIDEOUT_QTE_EVENT, false), new HandledRoute(ItemEventActions.REDEEM_PROFILE_REWARD, false), + new HandledRoute(ItemEventActions.SET_FAVORITE_ITEMS, false), ]; } @@ -93,6 +94,8 @@ export class InventoryItemEventRouter extends ItemEventRouterDefinition return this.hideoutCallbacks.handleQTEEvent(pmcData, body, sessionID); case ItemEventActions.REDEEM_PROFILE_REWARD: return this.inventoryCallbacks.redeemProfileReward(pmcData, body, sessionID); + case ItemEventActions.SET_FAVORITE_ITEMS: + return this.inventoryCallbacks.setFavoriteItem(pmcData, body, sessionID); default: throw new Error(`Unhandled event ${url}`); } diff --git a/project/src/services/ProfileFixerService.ts b/project/src/services/ProfileFixerService.ts index 13ca3188..f2123155 100644 --- a/project/src/services/ProfileFixerService.ts +++ b/project/src/services/ProfileFixerService.ts @@ -76,6 +76,7 @@ export class ProfileFixerService this.addMissingWallImprovements(pmcProfile); this.addMissingHideoutWallAreas(pmcProfile); this.addMissingGunStandContainerImprovements(pmcProfile); + this.addMissingHallOfFameContainerImprovements(pmcProfile); this.ensureGunStandLevelsMatch(pmcProfile); this.removeResourcesFromSlotsInHideoutWithoutLocationIndexValue(pmcProfile); @@ -284,6 +285,70 @@ export class ProfileFixerService } } + protected addMissingHallOfFameContainerImprovements(pmcProfile: IPmcData): void + { + const placeOfFameArea = pmcProfile.Hideout.Areas.find((x) => x.type === HideoutAreas.PLACE_OF_FAME); + if (!placeOfFameArea || placeOfFameArea.level === 0) + { + // No place of fame in profile or its level 0, skip + return; + } + + const db = this.databaseServer.getTables(); + const placeOfFameAreaDb = db.hideout.areas.find((x) => x.type === HideoutAreas.PLACE_OF_FAME); + const stageCurrentlyAt = placeOfFameAreaDb.stages[placeOfFameArea.level]; + const placeOfFameStashId = pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.PLACE_OF_FAME]; + + // `hideoutAreaStashes` empty but profile has built gun stand + if (!placeOfFameStashId && stageCurrentlyAt) + { + // Value is missing, add it + pmcProfile.Inventory.hideoutAreaStashes[HideoutAreas.PLACE_OF_FAME] = placeOfFameAreaDb._id; + + // Add stash item to profile + const placeOfFameStashItem = pmcProfile.Inventory.items.find((x) => x._id === placeOfFameAreaDb._id); + if (placeOfFameStashItem) + { + placeOfFameStashItem._tpl = stageCurrentlyAt.container; + this.logger.debug( + `Updated existing place of fame inventory stash: ${placeOfFameStashItem._id} tpl to ${stageCurrentlyAt.container}`, + ); + } + else + { + pmcProfile.Inventory.items.push({ _id: placeOfFameAreaDb._id, _tpl: stageCurrentlyAt.container }); + this.logger.debug( + `Added missing place of fame inventory stash: ${placeOfFameAreaDb._id} tpl to ${stageCurrentlyAt.container}`, + ); + } + + return; + } + + let stashItem = pmcProfile.Inventory.items?.find((x) => x._id === placeOfFameAreaDb._id); + if (!stashItem) + { + // Stand inventory stash item doesnt exist, add it + pmcProfile.Inventory.items.push( + { + _id: placeOfFameAreaDb._id, + _tpl: stageCurrentlyAt.container + } + ) + stashItem = pmcProfile.Inventory.items?.find((x) => x._id === placeOfFameAreaDb._id) + } + + // `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected + if (placeOfFameStashId && stashItem._tpl !== stageCurrentlyAt.container) + { + this.logger.debug( + `primary Stash tpl was: ${stashItem._tpl}, but should be ${stageCurrentlyAt.container}, updating`, + ); + // The id inside the profile does not match what the hideout db value is, out of sync, adjust + stashItem._tpl = stageCurrentlyAt.container; + } + } + protected ensureGunStandLevelsMatch(pmcProfile: IPmcData): void { // only proceed if stand is level 1 or above