From 6d7c4d95b62fce6d70563d067898338eedbbb4c2 Mon Sep 17 00:00:00 2001 From: Dev Date: Thu, 22 Aug 2024 17:48:39 +0100 Subject: [PATCH] Added further progress on cultist circle - now rewards items upon completion Now handles `HideoutDeleteProductionCommand` event, Deletes sacrificed items on craft start Set craft time to 30 secs for debugging --- project/src/callbacks/HideoutCallbacks.ts | 16 +++- project/src/controllers/HideoutController.ts | 78 ++++++++++++++++--- project/src/helpers/HideoutHelper.ts | 19 ++++- ...rcleOfCultistProductionStartRequestData.ts | 4 +- .../IHideoutDeleteProductionRequestData.ts | 5 ++ .../src/models/enums/HideoutEventActions.ts | 1 + .../item_events/HideoutItemEventRouter.ts | 3 + 7 files changed, 109 insertions(+), 17 deletions(-) create mode 100644 project/src/models/eft/hideout/IHideoutDeleteProductionRequestData.ts diff --git a/project/src/callbacks/HideoutCallbacks.ts b/project/src/callbacks/HideoutCallbacks.ts index 3c823588..58004e8d 100644 --- a/project/src/callbacks/HideoutCallbacks.ts +++ b/project/src/callbacks/HideoutCallbacks.ts @@ -5,6 +5,7 @@ import { IHandleQTEEventRequestData } from "@spt/models/eft/hideout/IHandleQTEEv import { IHideoutCancelProductionRequestData } from "@spt/models/eft/hideout/IHideoutCancelProductionRequestData"; import { IHideoutCircleOfCultistProductionStartRequestData } from "@spt/models/eft/hideout/IHideoutCircleOfCultistProductionStartRequestData"; import { IHideoutContinuousProductionStartRequestData } from "@spt/models/eft/hideout/IHideoutContinuousProductionStartRequestData"; +import { IHideoutDeleteProductionRequestData } from "@spt/models/eft/hideout/IHideoutDeleteProductionRequestData"; import { IHideoutImproveAreaRequestData } from "@spt/models/eft/hideout/IHideoutImproveAreaRequestData"; import { IHideoutPutItemInRequestData } from "@spt/models/eft/hideout/IHideoutPutItemInRequestData"; import { IHideoutScavCaseStartRequestData } from "@spt/models/eft/hideout/IHideoutScavCaseStartRequestData"; @@ -190,14 +191,25 @@ export class HideoutCallbacks implements OnUpdate { /** * Handle client/game/profile/items/moving - HideoutCircleOfCultistProductionStart */ - circleOfCultistProductionStart( + public circleOfCultistProductionStart( pmcData: IPmcData, request: IHideoutCircleOfCultistProductionStartRequestData, sessionId: string, - ): IItemEventRouterResponse | PromiseLike { + ): IItemEventRouterResponse { return this.hideoutController.circleOfCultistProductionStart(sessionId, pmcData, request); } + /** + * Handle client/game/profile/items/moving - HideoutDeleteProductionCommand + */ + hideoutDeleteProductionCommand( + pmcData: IPmcData, + request: IHideoutDeleteProductionRequestData, + sessionId: string, + ): IItemEventRouterResponse { + return this.hideoutController.hideoutDeleteProductionCommand(sessionId, pmcData, request); + } + public async onUpdate(timeSinceLastRun: number): Promise { if (timeSinceLastRun > this.hideoutConfig.runIntervalSeconds) { this.hideoutController.update(); diff --git a/project/src/controllers/HideoutController.ts b/project/src/controllers/HideoutController.ts index 66445623..13b8de10 100644 --- a/project/src/controllers/HideoutController.ts +++ b/project/src/controllers/HideoutController.ts @@ -14,6 +14,7 @@ import { IHideoutArea, Stage } from "@spt/models/eft/hideout/IHideoutArea"; import { IHideoutCancelProductionRequestData } from "@spt/models/eft/hideout/IHideoutCancelProductionRequestData"; import { IHideoutCircleOfCultistProductionStartRequestData } from "@spt/models/eft/hideout/IHideoutCircleOfCultistProductionStartRequestData"; import { IHideoutContinuousProductionStartRequestData } from "@spt/models/eft/hideout/IHideoutContinuousProductionStartRequestData"; +import { IHideoutDeleteProductionRequestData } from "@spt/models/eft/hideout/IHideoutDeleteProductionRequestData"; import { IHideoutImproveAreaRequestData } from "@spt/models/eft/hideout/IHideoutImproveAreaRequestData"; import { IHideoutProduction } from "@spt/models/eft/hideout/IHideoutProduction"; import { IHideoutPutItemInRequestData } from "@spt/models/eft/hideout/IHideoutPutItemInRequestData"; @@ -1256,7 +1257,7 @@ export class HideoutController { sessionId: string, pmcData: IPmcData, request: IHideoutCircleOfCultistProductionStartRequestData, - ): IItemEventRouterResponse | PromiseLike { + ): IItemEventRouterResponse { // Sparse, just has id const cultistCraftData = this.databaseService.getHideout().production.cultistRecipes[0]; const sacrificedItems: Item[] = this.getSacrificedItems(pmcData); @@ -1264,19 +1265,74 @@ export class HideoutController { // Create production in pmc profile this.hideoutHelper.registerCircleOfCultistProduction(sessionId, pmcData, cultistCraftData._id, sacrificedItems); - // What items can be rewarded by completion of craft - // TODO - how do we use this? maybe this is done in a later event? - const cultistStashDbItem = this.itemHelper.getItem(ItemTpl.HIDEOUTAREACONTAINER_CIRCLEOFCULTISTS_STASH_1); - const rewardItemPool = cultistStashDbItem[1]._props.Grids[0]._props.filters[0].Filter; - const output = this.eventOutputHolder.getOutput(sessionId); - // TODO - is this necessary? - // Do the items remain in the sacrifice window for duration of craft? // Remove sacrified items - // for (const rootItem of inventoryRootItemsInCultistGrid) { - // this.inventoryHelper.removeItem(pmcData, rootItem._id, sessionId, output); - // } + const slotId = "CircleOfCultistsGrid1"; + for (const item of sacrificedItems) { + if (item.slotId === slotId) { + this.inventoryHelper.removeItem(pmcData, item._id, sessionId, output); + } + } + + // What items can be rewarded by completion of craft + const cultistStashDbItem = this.itemHelper.getItem(ItemTpl.HIDEOUTAREACONTAINER_CIRCLEOFCULTISTS_STASH_1); + + // TODO: create own reward item pool as this is for items the circle accepts as sacrifice, NOT reward pool + const rewardItemPool = cultistStashDbItem[1]._props.Grids[0]._props.filters[0].Filter; + + // TODO, tie this into rouble cost of items sacrificed + const randomRewardItemCount = this.randomUtil.getInt(1, 4); + this.logger.warning(`cicle craft chose ${randomRewardItemCount} reward count`); + + // Create array of rewards + const rewards: Item[][] = []; + const cultistCircleStashId = pmcData.Inventory.hideoutAreaStashes[HideoutAreas.CIRCLE_OF_CULTISTS]; + for (let index = 0; index < randomRewardItemCount; index++) { + const itemTpl = this.randomUtil.getArrayValue(rewardItemPool); + const rewardItem: Item = { + _id: this.hashUtil.generate(), + _tpl: itemTpl, + parentId: cultistCircleStashId, + slotId: slotId, + upd: { + StackObjectsCount: 1, + SpawnedInSession: true, + }, + }; + + rewards.push([rewardItem]); + } + + // Get the container grid for cultist stash area + const containerGrid = this.inventoryHelper.getContainerSlotMap(cultistStashDbItem[1]._id); + const canAddToContainer = this.inventoryHelper.canPlaceItemsInContainer( + this.cloner.clone(containerGrid), // MUST clone grid before passing in as function modifies grid + rewards, + ); + + if (canAddToContainer) { + for (const itemToAdd of rewards) { + this.logger.warning(`Placing reward: ${itemToAdd[0]._tpl} in circle grid`); + this.inventoryHelper.placeItemInContainer(containerGrid, itemToAdd, cultistCircleStashId, slotId); + + // Add item + mods to output and profile inventory + output.profileChanges[sessionId].items.new.push(...itemToAdd); + pmcData.Inventory.items.push(...itemToAdd); + } + } + + return output; + } + + public hideoutDeleteProductionCommand( + sessionId: string, + pmcData: IPmcData, + request: IHideoutDeleteProductionRequestData, + ): IItemEventRouterResponse { + const output = this.eventOutputHolder.getOutput(sessionId); + + delete pmcData.Hideout.Production[request.recipeId]; return output; } diff --git a/project/src/helpers/HideoutHelper.ts b/project/src/helpers/HideoutHelper.ts index 0677aa30..f35b41aa 100644 --- a/project/src/helpers/HideoutHelper.ts +++ b/project/src/helpers/HideoutHelper.ts @@ -123,8 +123,8 @@ export class HideoutHelper { recipeId: string, sacrificedItems: Item[], ): void { - // TODO: hard coded 5 hour craft + no fuel use, where can we get this data - const cultistProduction = this.initProduction(recipeId, 18000, false, true); + // TODO: hard coded 5 hour (18000) craft + no fuel use, where can we get this data + const cultistProduction = this.initProduction(recipeId, 30, false, true); cultistProduction.GivenItemsInStart = sacrificedItems; // Add circle production to profile @@ -397,9 +397,24 @@ export class HideoutHelper { if (production.Progress < production.ProductionTime) { production.Progress += timeElapsedSeconds; + this.logger.warning(`circle craft progress is now ${production.Progress} of ${production.ProductionTime}`); + + // Check if craft is complete + if (production.Progress >= production.ProductionTime) { + this.flagCultistCircleCraftAsComplete(production); + this.logger.warning(`circle craft complete, AvailableForFinish set ot true`); + } + return; } + // Craft in complete + this.flagCultistCircleCraftAsComplete(production); + + this.logger.warning(`circle craft complete, AvailableForFinish set ot true`); + } + + protected flagCultistCircleCraftAsComplete(production: Productive) { // Craft is complete, flas as such production.AvailableForFinish = true; diff --git a/project/src/models/eft/hideout/IHideoutCircleOfCultistProductionStartRequestData.ts b/project/src/models/eft/hideout/IHideoutCircleOfCultistProductionStartRequestData.ts index 004d0083..6f7c9b72 100644 --- a/project/src/models/eft/hideout/IHideoutCircleOfCultistProductionStartRequestData.ts +++ b/project/src/models/eft/hideout/IHideoutCircleOfCultistProductionStartRequestData.ts @@ -1,4 +1,4 @@ -export type IHideoutCircleOfCultistProductionStartRequestData = { +export interface IHideoutCircleOfCultistProductionStartRequestData { Action: "HideoutCircleOfCultistProductionStart"; timestamp: number; -}; +} diff --git a/project/src/models/eft/hideout/IHideoutDeleteProductionRequestData.ts b/project/src/models/eft/hideout/IHideoutDeleteProductionRequestData.ts new file mode 100644 index 00000000..97714ded --- /dev/null +++ b/project/src/models/eft/hideout/IHideoutDeleteProductionRequestData.ts @@ -0,0 +1,5 @@ +export interface IHideoutDeleteProductionRequestData { + Action: "HideoutDeleteProductionCommand"; + recipeId: string; + timestamp: number; +} diff --git a/project/src/models/enums/HideoutEventActions.ts b/project/src/models/enums/HideoutEventActions.ts index cd42eff5..d58b568e 100644 --- a/project/src/models/enums/HideoutEventActions.ts +++ b/project/src/models/enums/HideoutEventActions.ts @@ -12,4 +12,5 @@ export enum HideoutEventActions { HIDEOUT_IMPROVE_AREA = "HideoutImproveArea", HIDEOUT_CANCEL_PRODUCTION_COMMAND = "HideoutCancelProductionCommand", HIDEOUT_CIRCLE_OF_CULTIST_PRODUCTION_START = "HideoutCircleOfCultistProductionStart", + HIDEOUT_DELETE_PRODUCTION_COMMAND = "HideoutDeleteProductionCommand", } diff --git a/project/src/routers/item_events/HideoutItemEventRouter.ts b/project/src/routers/item_events/HideoutItemEventRouter.ts index d317e1db..51e31439 100644 --- a/project/src/routers/item_events/HideoutItemEventRouter.ts +++ b/project/src/routers/item_events/HideoutItemEventRouter.ts @@ -26,6 +26,7 @@ export class HideoutItemEventRouter extends ItemEventRouterDefinition { new HandledRoute(HideoutEventActions.HIDEOUT_IMPROVE_AREA, false), new HandledRoute(HideoutEventActions.HIDEOUT_CANCEL_PRODUCTION_COMMAND, false), new HandledRoute(HideoutEventActions.HIDEOUT_CIRCLE_OF_CULTIST_PRODUCTION_START, false), + new HandledRoute(HideoutEventActions.HIDEOUT_DELETE_PRODUCTION_COMMAND, false), ]; } @@ -63,6 +64,8 @@ export class HideoutItemEventRouter extends ItemEventRouterDefinition { return this.hideoutCallbacks.cancelProduction(pmcData, body, sessionID); case HideoutEventActions.HIDEOUT_CIRCLE_OF_CULTIST_PRODUCTION_START: return this.hideoutCallbacks.circleOfCultistProductionStart(pmcData, body, sessionID); + case HideoutEventActions.HIDEOUT_DELETE_PRODUCTION_COMMAND: + return this.hideoutCallbacks.hideoutDeleteProductionCommand(pmcData, body, sessionID); default: throw new Error(`Unhandled event ${url} request: ${JSON.stringify(body)}`); }