92 lines
4.1 KiB
TypeScript
92 lines
4.1 KiB
TypeScript
import { MinMax } from "@spt/models/common/MinMax";
|
|
import { IRandomisedBotLevelResult } from "@spt/models/eft/bot/IRandomisedBotLevelResult";
|
|
import { IBotBase } from "@spt/models/eft/common/tables/IBotBase";
|
|
import { BotGenerationDetails } from "@spt/models/spt/bots/BotGenerationDetails";
|
|
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
|
import { DatabaseService } from "@spt/services/DatabaseService";
|
|
import { MathUtil } from "@spt/utils/MathUtil";
|
|
import { RandomUtil } from "@spt/utils/RandomUtil";
|
|
import { inject, injectable } from "tsyringe";
|
|
|
|
@injectable()
|
|
export class BotLevelGenerator {
|
|
constructor(
|
|
@inject("PrimaryLogger") protected logger: ILogger,
|
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
|
@inject("DatabaseService") protected databaseService: DatabaseService,
|
|
@inject("MathUtil") protected mathUtil: MathUtil,
|
|
) {}
|
|
|
|
/**
|
|
* Return a randomised bot level and exp value
|
|
* @param levelDetails Min and max of level for bot
|
|
* @param botGenerationDetails Details to help generate a bot
|
|
* @param bot Bot the level is being generated for
|
|
* @returns IRandomisedBotLevelResult object
|
|
*/
|
|
public generateBotLevel(
|
|
levelDetails: MinMax,
|
|
botGenerationDetails: BotGenerationDetails,
|
|
bot: IBotBase,
|
|
): IRandomisedBotLevelResult {
|
|
const expTable = this.databaseService.getGlobals().config.exp.level.exp_table;
|
|
const botLevelRange = this.getRelativeBotLevelRange(botGenerationDetails, levelDetails, expTable.length);
|
|
|
|
// Get random level based on the exp table.
|
|
let exp = 0;
|
|
const level = this.chooseBotLevel(botLevelRange.min, botLevelRange.max, 1, 1.15);
|
|
for (let i = 0; i < level; i++) {
|
|
exp += expTable[i].exp;
|
|
}
|
|
|
|
// Sprinkle in some random exp within the level, unless we are at max level.
|
|
if (level < expTable.length - 1) {
|
|
exp += this.randomUtil.getInt(0, expTable[level].exp - 1);
|
|
}
|
|
|
|
return { level, exp };
|
|
}
|
|
|
|
protected chooseBotLevel(min: number, max: number, shift: number, number: number): number {
|
|
return this.randomUtil.getBiasedRandomNumber(min, max, shift, number);
|
|
}
|
|
|
|
/**
|
|
* Return the min and max bot level based on a relative delta from the PMC level
|
|
* @param botGenerationDetails Details to help generate a bot
|
|
* @param levelDetails
|
|
* @param maxlevel Max level allowed
|
|
* @returns A MinMax of the lowest and highest level to generate the bots
|
|
*/
|
|
protected getRelativeBotLevelRange(
|
|
botGenerationDetails: BotGenerationDetails,
|
|
levelDetails: MinMax,
|
|
maxAvailableLevel: number,
|
|
): MinMax {
|
|
const minPossibleLevel =
|
|
botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
|
|
? Math.min(
|
|
Math.max(levelDetails.min, botGenerationDetails.locationSpecificPmcLevelOverride.min), // Biggest between json min and the botgen min
|
|
maxAvailableLevel, // Fallback if value above is crazy (default is 79)
|
|
)
|
|
: Math.min(levelDetails.min, maxAvailableLevel); // Not pmc with override or non-pmc
|
|
|
|
const maxPossibleLevel =
|
|
botGenerationDetails.isPmc && botGenerationDetails.locationSpecificPmcLevelOverride
|
|
? Math.min(botGenerationDetails.locationSpecificPmcLevelOverride.max, maxAvailableLevel) // Was a PMC and they have a level override
|
|
: Math.min(levelDetails.max, maxAvailableLevel); // Not pmc with override or non-pmc
|
|
|
|
let minLevel = botGenerationDetails.playerLevel - botGenerationDetails.botRelativeLevelDeltaMin;
|
|
let maxLevel = botGenerationDetails.playerLevel + botGenerationDetails.botRelativeLevelDeltaMax;
|
|
|
|
// Bound the level to the min/max possible
|
|
maxLevel = Math.min(Math.max(maxLevel, minPossibleLevel), maxPossibleLevel);
|
|
minLevel = Math.min(Math.max(minLevel, minPossibleLevel), maxPossibleLevel);
|
|
|
|
return {
|
|
min: minLevel,
|
|
max: maxLevel,
|
|
};
|
|
}
|
|
}
|