239 lines
9.2 KiB
TypeScript
239 lines
9.2 KiB
TypeScript
import { inject, injectable } from "tsyringe";
|
|
|
|
import { DialogueHelper } from "../helpers/DialogueHelper";
|
|
import { ItemHelper } from "../helpers/ItemHelper";
|
|
import { ProfileHelper } from "../helpers/ProfileHelper";
|
|
import { IPmcData } from "../models/eft/common/IPmcData";
|
|
import { Item } from "../models/eft/common/tables/IItem";
|
|
import { IGetInsuranceCostRequestData } from "../models/eft/insurance/IGetInsuranceCostRequestData";
|
|
import {
|
|
IGetInsuranceCostResponseData
|
|
} from "../models/eft/insurance/IGetInsuranceCostResponseData";
|
|
import { IInsureRequestData } from "../models/eft/insurance/IInsureRequestData";
|
|
import { IItemEventRouterResponse } from "../models/eft/itemEvent/IItemEventRouterResponse";
|
|
import { IProcessBuyTradeRequestData } from "../models/eft/trade/IProcessBuyTradeRequestData";
|
|
import { ConfigTypes } from "../models/enums/ConfigTypes";
|
|
import { IInsuranceConfig } from "../models/spt/config/IInsuranceConfig";
|
|
import { ILogger } from "../models/spt/utils/ILogger";
|
|
import { EventOutputHolder } from "../routers/EventOutputHolder";
|
|
import { ConfigServer } from "../servers/ConfigServer";
|
|
import { DatabaseServer } from "../servers/DatabaseServer";
|
|
import { SaveServer } from "../servers/SaveServer";
|
|
import { InsuranceService } from "../services/InsuranceService";
|
|
import { PaymentService } from "../services/PaymentService";
|
|
import { RandomUtil } from "../utils/RandomUtil";
|
|
import { TimeUtil } from "../utils/TimeUtil";
|
|
|
|
@injectable()
|
|
export class InsuranceController
|
|
{
|
|
protected insuranceConfig: IInsuranceConfig;
|
|
|
|
constructor(
|
|
@inject("WinstonLogger") protected logger: ILogger,
|
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
|
@inject("EventOutputHolder") protected eventOutputHolder: EventOutputHolder,
|
|
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
|
@inject("SaveServer") protected saveServer: SaveServer,
|
|
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
|
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
|
@inject("DialogueHelper") protected dialogueHelper: DialogueHelper,
|
|
@inject("PaymentService") protected paymentService: PaymentService,
|
|
@inject("InsuranceService") protected insuranceService: InsuranceService,
|
|
@inject("ConfigServer") protected configServer: ConfigServer
|
|
)
|
|
{
|
|
this.insuranceConfig = this.configServer.getConfig(ConfigTypes.INSURANCE);
|
|
}
|
|
|
|
/**
|
|
* Process insurance items prior to being given to player in mail
|
|
*/
|
|
public processReturn(): void
|
|
{
|
|
const time = this.timeUtil.getTimestamp();
|
|
|
|
// Process each profile in turn
|
|
for (const sessionID in this.saveServer.getProfiles())
|
|
{
|
|
const insuranceDetails = this.saveServer.getProfile(sessionID).insurance;
|
|
let insuredItemCount = insuranceDetails.length;
|
|
|
|
// Skip profile with no insurance items
|
|
if (insuredItemCount === 0)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Use count as array index
|
|
while (insuredItemCount-- > 0)
|
|
{
|
|
const insured = insuranceDetails[insuredItemCount];
|
|
|
|
// Return time not reached, skip
|
|
if (time < insured.scheduledTime)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Items to be removed from inventory
|
|
const toDelete: string[] = [];
|
|
|
|
// Loop over insurance items, find items to delete from player inventory
|
|
for (const insuredItem of insured.items)
|
|
{
|
|
if (this.itemShouldBeLost(insuredItem, insured.traderId, toDelete))
|
|
{
|
|
// Skip if not an item
|
|
const itemDbDetails = this.itemHelper.getItem(insuredItem._tpl);
|
|
if (!itemDbDetails[0])
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Is a mod and can't be edited in-raid
|
|
if (insuredItem.slotId !== "hideout" && !itemDbDetails[1]._props.RaidModdable)
|
|
{
|
|
continue;
|
|
}
|
|
|
|
// Remove item and its sub-items to prevent orphans
|
|
toDelete.push(...this.itemHelper.findAndReturnChildrenByItems(insured.items, insuredItem._id));
|
|
}
|
|
}
|
|
|
|
for (let index = insured.items.length - 1; index >= 0; --index)
|
|
{
|
|
if (toDelete.includes(insured.items[index]._id))
|
|
{
|
|
insured.items.splice(index, 1);
|
|
}
|
|
}
|
|
|
|
// No items to return as they all failed the above check, adjust insurance mail template
|
|
if (insured.items.length === 0)
|
|
{
|
|
const insuranceFailedTemplates = this.databaseServer.getTables().traders[insured.traderId].dialogue.insuranceFailed;
|
|
insured.messageContent.templateId = this.randomUtil.getArrayValue(insuranceFailedTemplates);
|
|
}
|
|
|
|
this.dialogueHelper.addDialogueMessage(insured.traderId, insured.messageContent, sessionID, insured.items);
|
|
|
|
// Remove insurance package from profile now we've processed it
|
|
insuranceDetails.splice(insuredItemCount, 1);
|
|
}
|
|
|
|
this.saveServer.getProfile(sessionID).insurance = insuranceDetails;
|
|
}
|
|
}
|
|
|
|
/**
|
|
* Should the passed in item be removed from player inventory
|
|
* @param insuredItem Insurued item to roll to lose
|
|
* @param traderId Trader the item was insured by
|
|
* @param itemsBeingDeleted All items to remove from player
|
|
* @returns True if item should be removed
|
|
*/
|
|
protected itemShouldBeLost(insuredItem: Item, traderId: string, itemsBeingDeleted: string[]): boolean
|
|
{
|
|
// Roll from 0 to 9999, then divide it by 100: 9999 = 99.99%
|
|
const returnChance = this.randomUtil.getInt(0, 9999) / 100;
|
|
const traderReturnChance = this.insuranceConfig.returnChancePercent[traderId];
|
|
|
|
const slotIdsThatCanFail = this.insuranceConfig.slotIdsWithChanceOfNotReturning;
|
|
return (slotIdsThatCanFail.includes(insuredItem.slotId)) && returnChance >= traderReturnChance && !itemsBeingDeleted.includes(insuredItem._id);
|
|
}
|
|
|
|
/**
|
|
* Add insurance to an item
|
|
* @param pmcData Player profile
|
|
* @param body Insurance request
|
|
* @param sessionID Session id
|
|
* @returns IItemEventRouterResponse object to send to client
|
|
*/
|
|
public insure(pmcData: IPmcData, body: IInsureRequestData, sessionID: string): IItemEventRouterResponse
|
|
{
|
|
let output = this.eventOutputHolder.getOutput(sessionID);
|
|
const itemsToPay = [];
|
|
const inventoryItemsHash = {};
|
|
|
|
for (const item of pmcData.Inventory.items)
|
|
{
|
|
inventoryItemsHash[item._id] = item;
|
|
}
|
|
|
|
// get the price of all items
|
|
for (const key of body.items)
|
|
{
|
|
itemsToPay.push({
|
|
id: inventoryItemsHash[key]._id,
|
|
count: Math.round(this.insuranceService.getPremium(pmcData, inventoryItemsHash[key], body.tid))
|
|
});
|
|
}
|
|
|
|
const options: IProcessBuyTradeRequestData = {
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
scheme_items: itemsToPay,
|
|
tid: body.tid,
|
|
Action: "",
|
|
type: "",
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
item_id: "",
|
|
count: 0,
|
|
// eslint-disable-next-line @typescript-eslint/naming-convention
|
|
scheme_id: 0
|
|
};
|
|
|
|
// pay for the item insurance
|
|
output = this.paymentService.payMoney(pmcData, options, sessionID, output);
|
|
if (output.warnings.length > 0)
|
|
{
|
|
return output;
|
|
}
|
|
|
|
// add items to InsuredItems list once money has been paid
|
|
for (const key of body.items)
|
|
{
|
|
pmcData.InsuredItems.push({
|
|
tid: body.tid,
|
|
itemId: inventoryItemsHash[key]._id
|
|
});
|
|
}
|
|
|
|
return output;
|
|
}
|
|
|
|
/**
|
|
* Calculate insurance cost
|
|
* @param info request object
|
|
* @param sessionID session id
|
|
* @returns IGetInsuranceCostResponseData object to send to client
|
|
*/
|
|
public cost(info: IGetInsuranceCostRequestData, sessionID: string): IGetInsuranceCostResponseData
|
|
{
|
|
const output: IGetInsuranceCostResponseData = {};
|
|
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
|
const inventoryItemsHash: Record<string, Item> = {};
|
|
|
|
for (const item of pmcData.Inventory.items)
|
|
{
|
|
inventoryItemsHash[item._id] = item;
|
|
}
|
|
|
|
for (const trader of info.traders)
|
|
{
|
|
const items = {};
|
|
|
|
for (const key of info.items)
|
|
{
|
|
items[inventoryItemsHash[key]._tpl] = Math.round(this.insuranceService.getPremium(pmcData, inventoryItemsHash[key], trader));
|
|
}
|
|
|
|
output[trader] = items;
|
|
}
|
|
|
|
return output;
|
|
}
|
|
}
|