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
This commit is contained in:
Dev 2024-08-22 17:48:39 +01:00
parent eccf4ee969
commit 6d7c4d95b6
7 changed files with 109 additions and 17 deletions

View File

@ -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> {
): 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<boolean> {
if (timeSinceLastRun > this.hideoutConfig.runIntervalSeconds) {
this.hideoutController.update();

View File

@ -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> {
): 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;
}

View File

@ -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;

View File

@ -1,4 +1,4 @@
export type IHideoutCircleOfCultistProductionStartRequestData = {
export interface IHideoutCircleOfCultistProductionStartRequestData {
Action: "HideoutCircleOfCultistProductionStart";
timestamp: number;
};
}

View File

@ -0,0 +1,5 @@
export interface IHideoutDeleteProductionRequestData {
Action: "HideoutDeleteProductionCommand";
recipeId: string;
timestamp: number;
}

View File

@ -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",
}

View File

@ -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)}`);
}