Refactor functions (!90)

(cherry picked from commit f6fc6e41c0)

Co-authored-by: Dev <dev@noreply.dev.sp-tarkov.com>
Reviewed-on: https://dev.sp-tarkov.com/SPT-AKI/Server/pulls/90
This commit is contained in:
chomp 2023-04-22 22:41:04 +00:00
parent 2bc582d65c
commit 7974e4531b
5 changed files with 168 additions and 75 deletions

View File

@ -26,7 +26,7 @@ export class DialogueController
const profiles = this.saveServer.getProfiles();
for (const sessionID in profiles)
{
this.removeExpiredItems(sessionID);
this.removeExpiredItemsFromMessages(sessionID);
}
}
@ -220,20 +220,40 @@ export class DialogueController
}
/**
* Delete expired items. triggers when updating traders.
* @param sessionID Session id
* Delete expired items from all messages in player profile. triggers when updating traders.
* @param sessionId Session id
*/
protected removeExpiredItems(sessionID: string): void
protected removeExpiredItemsFromMessages(sessionId: string): void
{
for (const dialogueId in this.saveServer.getProfile(sessionID).dialogues)
for (const dialogueId in this.saveServer.getProfile(sessionId).dialogues)
{
for (const message of this.saveServer.getProfile(sessionID).dialogues[dialogueId].messages)
this.removeExpiredItemsFromMessage(sessionId, dialogueId);
}
}
/**
* Removes expired items from a message in player profile
* @param sessionId Session id
* @param dialogueId Dialog id
*/
protected removeExpiredItemsFromMessage(sessionId: string, dialogueId: string): void
{
for (const message of this.saveServer.getProfile(sessionId).dialogues[dialogueId].messages)
{
if (this.messageHasExpired(message))
{
if ((this.timeUtil.getTimestamp()) > (message.dt + message.maxStorageTime))
{
message.items = {};
}
message.items = {};
}
}
}
/**
* Has a dialog message expired
* @param message Message to check expiry of
* @returns true or false
*/
protected messageHasExpired(message: Message): boolean
{
return (this.timeUtil.getTimestamp()) > (message.dt + message.maxStorageTime);
}
}

View File

@ -327,67 +327,38 @@ export class RagfairController
}
}
public addPlayerOffer(pmcData: IPmcData, info: IAddOfferRequestData, sessionID: string): IItemEventRouterResponse
/**
* List item(s) on flea for sale
* @param pmcData Player profile
* @param offerRequest Flea list creatio offer
* @param sessionID Session id
* @returns IItemEventRouterResponse
*/
public addPlayerOffer(pmcData: IPmcData, offerRequest: IAddOfferRequestData, sessionID: string): IItemEventRouterResponse
{
let output = this.eventOutputHolder.getOutput(sessionID);
let requirementsPriceInRub = 0;
const invItems: Item[] = [];
if (!info?.items || info.items.length === 0)
const validationMessage = "";
if (!this.isValidPlayerOfferRequest(offerRequest, validationMessage))
{
this.logger.error(this.localisationService.getText("ragfair-invalid_player_offer_request"));
return this.httpResponse.appendErrorToOutput(output);
return this.httpResponse.appendErrorToOutput(output, validationMessage);
}
if (!info.requirements)
// Get an array of items from player inventory to list on flea
const getItemsFromInventoryErrorMessage = "";
const itemsInInventoryToList = this.getItemsToListOnFleaFromInventory(pmcData, offerRequest.items, getItemsFromInventoryErrorMessage);
if (!itemsInInventoryToList)
{
return this.httpResponse.appendErrorToOutput(output, this.localisationService.getText("ragfair-unable_to_place_offer_with_no_requirements"));
}
for (const item of info.requirements)
{
const requestedItemTpl = item._tpl;
if (this.paymentHelper.isMoneyTpl(requestedItemTpl))
{
requirementsPriceInRub += this.handbookHelper.inRUB(item.count, requestedItemTpl);
}
else
{
requirementsPriceInRub += this.ragfairPriceService.getDynamicPriceForItem(requestedItemTpl) * item.count;
}
}
// Count how many items are being sold and multiply the requested amount accordingly
for (const itemId of info.items)
{
let item = pmcData.Inventory.items.find(i => i._id === itemId);
if (item === undefined)
{
this.logger.error(this.localisationService.getText("ragfair-unable_to_find_item_in_inventory", {id: itemId}));
return this.httpResponse.appendErrorToOutput(output);
}
item = this.itemHelper.fixItemStackCount(item);
invItems.push(...this.itemHelper.findAndReturnChildrenAsItems(pmcData.Inventory.items, itemId));
}
if (!invItems?.length)
{
this.logger.error(this.localisationService.getText("ragfair-unable_to_find_requested_items_in_inventory"));
return this.httpResponse.appendErrorToOutput(output);
this.httpResponse.appendErrorToOutput(output, getItemsFromInventoryErrorMessage);
}
// Preparations are done, create the offer
const offer = this.createPlayerOffer(this.saveServer.getProfile(sessionID), info.requirements, this.ragfairHelper.mergeStackable(invItems), info.sellInOnePiece, requirementsPriceInRub);
const requirementsPriceInRub = this.calculateRequirementsPriceInRub(offerRequest.requirements);
const offer = this.createPlayerOffer(this.saveServer.getProfile(sessionID), offerRequest.requirements, this.ragfairHelper.mergeStackable(itemsInInventoryToList), offerRequest.sellInOnePiece, requirementsPriceInRub);
const rootItem = offer.items[0];
const qualityMultiplier = this.itemHelper.getItemQualityModifier(rootItem);
const averageOfferPrice = this.ragfairPriceService.getFleaPriceForItem(rootItem._tpl) * rootItem.upd.StackObjectsCount * qualityMultiplier;
const itemStackCount = (!info.sellInOnePiece) ? offer.items[0].upd.StackObjectsCount : 1;
const itemStackCount = (!offerRequest.sellInOnePiece) ? offer.items[0].upd.StackObjectsCount : 1;
const singleOfferValue = averageOfferPrice / itemStackCount;
let sellChance = this.ragfairConfig.sell.chance.base * qualityMultiplier;
@ -397,7 +368,7 @@ export class RagfairController
// Subtract flea market fee from stash
if (this.ragfairConfig.sell.fees)
{
const tax = this.ragfairTaxHelper.calculateTax(rootItem, pmcData, requirementsPriceInRub, itemStackCount, info.sellInOnePiece);
const tax = this.ragfairTaxHelper.calculateTax(rootItem, pmcData, requirementsPriceInRub, itemStackCount, offerRequest.sellInOnePiece);
const request: IProcessBuyTradeRequestData = {
tid: "ragfair",
@ -428,7 +399,7 @@ export class RagfairController
output.profileChanges[sessionID].ragFairOffers.push(offer);
// Remove items from inventory after creating offer
for (const itemToRemove of info.items)
for (const itemToRemove of offerRequest.items)
{
this.inventoryHelper.removeItem(pmcData, itemToRemove, sessionID, output);
}
@ -436,6 +407,95 @@ export class RagfairController
return output;
}
/**
* Is the item to be listed on the flea valid
* @param offerRequest Client offer request
* @param errorMessage message to show to player when offer is invalid
* @returns Is offer valid
*/
protected isValidPlayerOfferRequest(offerRequest: IAddOfferRequestData, errorMessage: string): boolean
{
if (!offerRequest?.items || offerRequest.items.length === 0)
{
errorMessage = this.localisationService.getText("ragfair-invalid_player_offer_request");
this.logger.error(errorMessage);
return false;
}
if (!offerRequest.requirements)
{
errorMessage = this.localisationService.getText("ragfair-unable_to_place_offer_with_no_requirements");
this.logger.error(errorMessage);
return false;
}
return true;
}
/**
* Get the handbook price in roubles for the items being listed
* @param requirements
* @returns Rouble price
*/
protected calculateRequirementsPriceInRub(requirements: Requirement[]): number
{
let requirementsPriceInRub = 0;
for (const item of requirements)
{
const requestedItemTpl = item._tpl;
if (this.paymentHelper.isMoneyTpl(requestedItemTpl))
{
requirementsPriceInRub += this.handbookHelper.inRUB(item.count, requestedItemTpl);
}
else
{
requirementsPriceInRub += this.ragfairPriceService.getDynamicPriceForItem(requestedItemTpl) * item.count;
}
}
return requirementsPriceInRub;
}
/**
* Using item ids from flea offer request, find corrispnding items from player inventory and return as array
* @param pmcData Player profile
* @param itemIdsFromFleaOfferRequest Ids from request
* @param errorMessage if item is not found, add error message to this parameter
* @returns Array of items from player inventory
*/
protected getItemsToListOnFleaFromInventory(pmcData: IPmcData, itemIdsFromFleaOfferRequest: string[], errorMessage: string): Item[]
{
const itemsToReturn = [];
// Count how many items are being sold and multiply the requested amount accordingly
for (const itemId of itemIdsFromFleaOfferRequest)
{
let item = pmcData.Inventory.items.find(i => i._id === itemId);
if (!item)
{
errorMessage = this.localisationService.getText("ragfair-unable_to_find_item_in_inventory", {id: itemId});
this.logger.error(errorMessage);
return null;
}
item = this.itemHelper.fixItemStackCount(item);
itemsToReturn.push(...this.itemHelper.findAndReturnChildrenAsItems(pmcData.Inventory.items, itemId));
}
if (!itemsToReturn?.length)
{
errorMessage = this.localisationService.getText("ragfair-unable_to_find_requested_items_in_inventory");
this.logger.error(errorMessage);
return null;
}
return itemsToReturn;
}
public createPlayerOffer(profile: IAkiProfile, requirements: Requirement[], items: Item[], sellInOnePiece: boolean, amountToSend: number): IRagfairOffer
{
const loyalLevel = 1;

View File

@ -13,6 +13,11 @@ import { LocalisationService } from "../services/LocalisationService";
import { HashUtil } from "../utils/HashUtil";
import { RandomUtil } from "../utils/RandomUtil";
type ItemLimit = {
current: number,
max: number
};
@injectable()
export class LootGenerator
{
@ -71,19 +76,18 @@ export class LootGenerator
}
/**
* Construct item limit record to hold max and current item count
* Construct item limit record to hold max and current item count for each item type
* @param limits limits as defined in config
* @returns record, key: item tplId, value: current/max item count allowed
*/
protected initItemLimitCounter(limits: Record<string, number>): Record<string, {current: number, max: number}>
protected initItemLimitCounter(limits: Record<string, number>): Record<string, ItemLimit>
{
const itemTypeCounts: Record<string, {current: number, max: number}> = {};
for (const x in limits)
const itemTypeCounts: Record<string, ItemLimit> = {};
for (const itemTypeId in limits)
{
itemTypeCounts[x] = {
itemTypeCounts[itemTypeId] = {
current: 0,
max: limits[x]
max: limits[itemTypeId]
};
}

View File

@ -207,7 +207,7 @@ export class RagfairServerHelper
}
// generated offer
// recurse if name is longer than max characters allowed (15 characters)
// recurivse if name is longer than max characters allowed (15 characters)
const type = (this.randomUtil.getInt(0, 1) === 0) ? "usec" : "bear";
const name = this.randomUtil.getStringArrayValue(this.databaseServer.getTables().bots.types[type].firstName);
return (name.length > 15) ? this.getNickname(userID) : name;

View File

@ -126,17 +126,26 @@ export class TraderHelper
const traderInfo = pmcData.TradersInfo[traderId];
// Add standing to trader
traderInfo.standing += standingToAdd;
// dont allow standing to fall below 0
if (traderInfo.standing < 0)
{
traderInfo.standing = 0;
}
traderInfo.standing = this.addStandingValuesTogether(traderInfo.standing, standingToAdd);
this.lvlUp(traderId, sessionId);
}
/**
* Add standing to current standing and clamp value if it goes too low
* @param currentStanding current trader standing
* @param standingToAdd stansding to add to trader standing
* @returns current standing + added standing (clamped if needed)
*/
protected addStandingValuesTogether(currentStanding: number, standingToAdd: number): number
{
const newStanding = currentStanding + standingToAdd;
return newStanding < 0
? 0
: newStanding;
}
/**
* Calculate traders level based on exp amount and increments level if over threshold
* @param traderID trader to process