Server/project/src/controllers/CustomizationController.ts

233 lines
8.1 KiB
TypeScript
Raw Normal View History

2023-03-03 16:23:46 +01:00
import { inject, injectable } from "tsyringe";
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
import { ISuit } from "@spt-aki/models/eft/common/tables/ITrader";
import { ClothingItem, IBuyClothingRequestData } from "@spt-aki/models/eft/customization/IBuyClothingRequestData";
import { IWearClothingRequestData } from "@spt-aki/models/eft/customization/IWearClothingRequestData";
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
import { SaveServer } from "@spt-aki/servers/SaveServer";
import { LocalisationService } from "@spt-aki/services/LocalisationService";
2023-03-03 16:23:46 +01:00
@injectable()
export class CustomizationController
{
protected readonly clothingIds = {
lowerParentId: "5cd944d01388ce000a659df9",
upperParentId: "5cd944ca1388ce03a44dc2a4",
};
2023-03-03 16:23:46 +01:00
constructor(
@inject("WinstonLogger") protected logger: ILogger,
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
@inject("SaveServer") protected saveServer: SaveServer,
@inject("LocalisationService") protected localisationService: LocalisationService,
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
2023-03-03 16:23:46 +01:00
)
{}
/**
* Get purchasable clothing items from trader that match players side (usec/bear)
* @param traderID trader to look up clothing for
* @param sessionID Session id
* @returns ISuit array
*/
2023-03-03 16:23:46 +01:00
public getTraderSuits(traderID: string, sessionID: string): ISuit[]
{
const pmcData: IPmcData = this.profileHelper.getPmcProfile(sessionID);
const templates = this.databaseServer.getTables().templates.customization;
const suits = this.databaseServer.getTables().traders[traderID].suits;
// Get an inner join of clothing from templates.customization and ragmans suits array
const matchingSuits = suits.filter((x) => x.suiteId in templates);
2023-03-03 16:23:46 +01:00
// Return all suits that have a side array containing the players side (usec/bear)
return matchingSuits.filter((x) => templates[x.suiteId]._props.Side.includes(pmcData.Info.Side));
2023-03-03 16:23:46 +01:00
}
/**
* Handle CustomizationWear event
* Equip one to many clothing items to player
*/
public wearClothing(
pmcData: IPmcData,
wearClothingRequest: IWearClothingRequestData,
sessionID: string,
): IItemEventRouterResponse
2023-03-03 16:23:46 +01:00
{
2023-04-23 12:38:57 +02:00
for (const suitId of wearClothingRequest.suites)
2023-03-03 16:23:46 +01:00
{
// Find desired clothing item in db
2023-04-23 12:38:57 +02:00
const dbSuit = this.databaseServer.getTables().templates.customization[suitId];
2023-03-03 16:23:46 +01:00
// Legs
if (dbSuit._parent === this.clothingIds.lowerParentId)
2023-03-03 16:23:46 +01:00
{
2023-04-23 12:38:57 +02:00
pmcData.Customization.Feet = dbSuit._props.Feet;
2023-03-03 16:23:46 +01:00
}
// Torso
if (dbSuit._parent === this.clothingIds.upperParentId)
2023-03-03 16:23:46 +01:00
{
2023-04-23 12:38:57 +02:00
pmcData.Customization.Body = dbSuit._props.Body;
pmcData.Customization.Hands = dbSuit._props.Hands;
2023-03-03 16:23:46 +01:00
}
}
return this.eventOutputHolder.getOutput(sessionID);
}
/**
* Handle CustomizationBuy event
* Purchase/unlock a clothing item from a trader
* @param pmcData Player profile
* @param buyClothingRequest Request object
* @param sessionId Session id
* @returns IItemEventRouterResponse
*/
public buyClothing(
pmcData: IPmcData,
buyClothingRequest: IBuyClothingRequestData,
sessionId: string,
): IItemEventRouterResponse
2023-03-03 16:23:46 +01:00
{
const db = this.databaseServer.getTables();
2023-04-23 13:17:18 +02:00
const output = this.eventOutputHolder.getOutput(sessionId);
2023-03-03 16:23:46 +01:00
2023-04-23 13:17:18 +02:00
const traderOffer = this.getTraderClothingOffer(sessionId, buyClothingRequest.offer);
if (!traderOffer)
{
this.logger.error(
this.localisationService.getText("customisation-unable_to_find_suit_by_id", buyClothingRequest.offer),
);
2023-04-23 13:17:18 +02:00
return output;
}
2023-03-03 16:23:46 +01:00
2023-04-23 13:17:18 +02:00
const suitId = traderOffer.suiteId;
if (this.outfitAlreadyPurchased(suitId, sessionId))
2023-03-03 16:23:46 +01:00
{
const suitDetails = db.templates.customization[suitId];
this.logger.error(
this.localisationService.getText("customisation-item_already_purchased", {
itemId: suitDetails._id,
itemName: suitDetails._name,
}),
);
2023-03-03 16:23:46 +01:00
return output;
}
2023-04-23 13:17:18 +02:00
// Pay for items
this.payForClothingItems(sessionId, pmcData, buyClothingRequest.items, output);
2023-03-03 16:23:46 +01:00
2023-04-23 13:17:18 +02:00
// Add clothing to profile
this.saveServer.getProfile(sessionId).suits.push(suitId);
2023-03-03 16:23:46 +01:00
2023-04-23 13:17:18 +02:00
return output;
}
2023-03-03 16:23:46 +01:00
2023-04-23 13:17:18 +02:00
protected getTraderClothingOffer(sessionId: string, offerId: string): ISuit
{
return this.getAllTraderSuits(sessionId).find((x) => x._id === offerId);
2023-04-23 13:17:18 +02:00
}
/**
* Has an outfit been purchased by a player
* @param suitId clothing id
* @param sessionID Session id of profile to check for clothing in
* @returns true if already purchased
2023-04-23 13:17:18 +02:00
*/
protected outfitAlreadyPurchased(suitId: string, sessionID: string): boolean
{
return this.saveServer.getProfile(sessionID).suits.includes(suitId);
}
/**
* Update output object and player profile with purchase details
* @param sessionId Session id
* @param pmcData Player profile
* @param clothingItems Clothing purchased
* @param output Client response
*/
protected payForClothingItems(
sessionId: string,
pmcData: IPmcData,
clothingItems: ClothingItem[],
output: IItemEventRouterResponse,
): void
2023-04-23 13:17:18 +02:00
{
for (const sellItem of clothingItems)
{
this.payForClothingItem(sessionId, pmcData, sellItem, output);
}
}
/**
* Update output object and player profile with purchase details for single piece of clothing
* @param sessionId Session id
* @param pmcData Player profile
* @param clothingItem Clothing item purchased
* @param output Client response
*/
protected payForClothingItem(
sessionId: string,
pmcData: IPmcData,
clothingItem: ClothingItem,
output: IItemEventRouterResponse,
): void
2023-04-23 13:17:18 +02:00
{
const relatedItem = pmcData.Inventory.items.find((x) => x._id === clothingItem.id);
2023-04-23 13:17:18 +02:00
if (!relatedItem)
{
this.logger.error(
this.localisationService.getText(
"customisation-unable_to_find_clothing_item_in_inventory",
clothingItem.id,
),
);
2023-04-23 13:17:18 +02:00
return;
2023-03-03 16:23:46 +01:00
}
2023-04-23 13:17:18 +02:00
if (clothingItem.del === true)
{
output.profileChanges[sessionId].items.del.push(relatedItem);
pmcData.Inventory.items.splice(pmcData.Inventory.items.indexOf(relatedItem), 1);
}
2023-03-03 16:23:46 +01:00
2023-04-23 13:17:18 +02:00
if (relatedItem.upd.StackObjectsCount > clothingItem.count)
{
relatedItem.upd.StackObjectsCount -= clothingItem.count;
2023-04-23 13:17:18 +02:00
output.profileChanges[sessionId].items.change.push({
_id: relatedItem._id,
_tpl: relatedItem._tpl,
parentId: relatedItem.parentId,
slotId: relatedItem.slotId,
location: relatedItem.location,
upd: { StackObjectsCount: relatedItem.upd.StackObjectsCount },
2023-04-23 13:17:18 +02:00
});
}
2023-03-03 16:23:46 +01:00
}
protected getAllTraderSuits(sessionID: string): ISuit[]
{
const traders = this.databaseServer.getTables().traders;
let result: ISuit[] = [];
for (const traderID in traders)
{
if (traders[traderID].base.customization_seller === true)
{
result = [...result, ...this.getTraderSuits(traderID, sessionID)];
}
}
return result;
}
}