Loosened bot name limit to 19 characters

Moved value into config
Added `botConfig.botRolesThatMustHaveUniqueName`

Refactored `getPmcNicknameOfMaxLength()`, removed all recursion + handles when no name is below desired length
Refactored `generateUniqueBotNickname()` to handle PMC names differently, use centralised pmc name function

Updated ragfair to utilise maxlength value from bot config
This commit is contained in:
Dev 2024-10-18 11:39:51 +01:00
parent d2239db64b
commit 9c58e2e0e5
8 changed files with 61 additions and 31 deletions

View File

@ -2835,5 +2835,7 @@
"max": 100 "max": 100
} }
} }
} },
"botNameLengthLimit": 19,
"botRolesThatMustHaveUniqueName": ["assault", "pmcusec", "pmcbear"]
} }

View File

@ -910,7 +910,7 @@ export class GameController {
const bots = this.databaseService.getBots().types; const bots = this.databaseService.getBots().types;
// Official names can only be 15 chars in length // Official names can only be 15 chars in length
if (playerName.length > 15) { if (playerName.length > this.botConfig.botNameLengthLimit) {
return; return;
} }

View File

@ -152,7 +152,7 @@ export class BotGenerator {
botJsonTemplate: IBotType, botJsonTemplate: IBotType,
botGenerationDetails: BotGenerationDetails, botGenerationDetails: BotGenerationDetails,
): IBotBase { ): IBotBase {
const botRole = botGenerationDetails.role.toLowerCase(); const botRoleLowercase = botGenerationDetails.role.toLowerCase();
const botLevel = this.botLevelGenerator.generateBotLevel( const botLevel = this.botLevelGenerator.generateBotLevel(
botJsonTemplate.experience.level, botJsonTemplate.experience.level,
botGenerationDetails, botGenerationDetails,
@ -169,12 +169,10 @@ export class BotGenerator {
} }
bot.Info.Nickname = this.botNameService.generateUniqueBotNickname( bot.Info.Nickname = this.botNameService.generateUniqueBotNickname(
botJsonTemplate.firstName, botJsonTemplate,
botJsonTemplate.lastName,
botGenerationDetails, botGenerationDetails,
botRole, botRoleLowercase,
["assault", "pmcusec", "pmcbear"], this.botConfig.botRolesThatMustHaveUniqueName,
sessionId,
); );
if (!this.seasonalEventService.christmasEventEnabled()) { if (!this.seasonalEventService.christmasEventEnabled()) {
@ -213,18 +211,19 @@ export class BotGenerator {
} }
} }
// Add drip
this.setBotAppearance(bot, botJsonTemplate.appearance, botGenerationDetails); this.setBotAppearance(bot, botJsonTemplate.appearance, botGenerationDetails);
bot.Inventory = this.botInventoryGenerator.generateInventory( bot.Inventory = this.botInventoryGenerator.generateInventory(
sessionId, sessionId,
botJsonTemplate, botJsonTemplate,
botRole, botRoleLowercase,
botGenerationDetails.isPmc, botGenerationDetails.isPmc,
botLevel.level, botLevel.level,
bot.Info.GameVersion, bot.Info.GameVersion,
); );
if (this.botConfig.botRolesWithDogTags.includes(botRole)) { if (this.botConfig.botRolesWithDogTags.includes(botRoleLowercase)) {
this.addDogtagToBot(bot); this.addDogtagToBot(bot);
} }

View File

@ -14,6 +14,7 @@ import { BaseClasses } from "@spt/models/enums/BaseClasses";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { MemberCategory } from "@spt/models/enums/MemberCategory"; import { MemberCategory } from "@spt/models/enums/MemberCategory";
import { Money } from "@spt/models/enums/Money"; import { Money } from "@spt/models/enums/Money";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import { import {
Condition, Condition,
Dynamic, Dynamic,
@ -37,6 +38,7 @@ import { inject, injectable } from "tsyringe";
@injectable() @injectable()
export class RagfairOfferGenerator { export class RagfairOfferGenerator {
protected ragfairConfig: IRagfairConfig; protected ragfairConfig: IRagfairConfig;
protected botConfig: IBotConfig;
protected allowedFleaPriceItemsForBarter: { tpl: string; price: number }[]; protected allowedFleaPriceItemsForBarter: { tpl: string; price: number }[];
/** Internal counter to ensure each offer created has a unique value for its intId property */ /** Internal counter to ensure each offer created has a unique value for its intId property */
@ -65,6 +67,7 @@ export class RagfairOfferGenerator {
@inject("PrimaryCloner") protected cloner: ICloner, @inject("PrimaryCloner") protected cloner: ICloner,
) { ) {
this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR); this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR);
this.botConfig = this.configServer.getConfig(ConfigTypes.BOT);
} }
/** /**
@ -192,11 +195,11 @@ export class RagfairOfferGenerator {
}; };
} }
// Regular old fake pmc offer // Fake pmc offer
return { return {
id: userID, id: userID,
memberType: MemberCategory.DEFAULT, memberType: MemberCategory.DEFAULT,
nickname: this.botHelper.getPmcNicknameOfMaxLength(userID, 50), nickname: this.botHelper.getPmcNicknameOfMaxLength(this.botConfig.botNameLengthLimit),
rating: this.randomUtil.getFloat( rating: this.randomUtil.getFloat(
this.ragfairConfig.dynamic.rating.min, this.ragfairConfig.dynamic.rating.min,
this.ragfairConfig.dynamic.rating.max, this.ragfairConfig.dynamic.rating.max,

View File

@ -7,6 +7,7 @@ import { ILogger } from "@spt/models/spt/utils/ILogger";
import { ConfigServer } from "@spt/servers/ConfigServer"; import { ConfigServer } from "@spt/servers/ConfigServer";
import { DatabaseService } from "@spt/services/DatabaseService"; import { DatabaseService } from "@spt/services/DatabaseService";
import { RandomUtil } from "@spt/utils/RandomUtil"; import { RandomUtil } from "@spt/utils/RandomUtil";
import { max } from "date-fns";
import { inject, injectable } from "tsyringe"; import { inject, injectable } from "tsyringe";
@injectable() @injectable()
@ -168,10 +169,24 @@ export class BotHelper {
return this.randomUtil.getChance100(this.pmcConfig.isUsec) ? "Usec" : "Bear"; return this.randomUtil.getChance100(this.pmcConfig.isUsec) ? "Usec" : "Bear";
} }
public getPmcNicknameOfMaxLength(userId: string, maxLength: number): string { /**
// recurivse if name is longer than max characters allowed (15 characters) * Get a name from a PMC that fits the desired length
const randomType = this.randomUtil.getInt(0, 1) === 0 ? "usec" : "bear"; * @param maxLength Max length of name, inclusive
const name = this.randomUtil.getStringArrayValue(this.databaseService.getBots().types[randomType].firstName); * @param side OPTIONAL - what side PMC to get name from (usec/bear)
return name.length > maxLength ? this.getPmcNicknameOfMaxLength(userId, maxLength) : name; * @returns name of PMC
*/
public getPmcNicknameOfMaxLength(maxLength: number, side?: string): string {
const randomType = side ? side : this.randomUtil.getInt(0, 1) === 0 ? "usec" : "bear";
const allNames = this.databaseService.getBots().types[randomType].firstName;
const filteredNames = allNames.filter((name) => name.length <= maxLength);
if (filteredNames.length === 0) {
this.logger.warning(
`Unable to filter: ${randomType} PMC names to only those under: ${maxLength}, none found that match that criteria, selecting from entire name pool instead`,
);
return this.randomUtil.getStringArrayValue(allNames);
}
return this.randomUtil.getStringArrayValue(filteredNames);
} }
} }

View File

@ -21,6 +21,7 @@ import { MemberCategory } from "@spt/models/enums/MemberCategory";
import { MessageType } from "@spt/models/enums/MessageType"; import { MessageType } from "@spt/models/enums/MessageType";
import { RagfairSort } from "@spt/models/enums/RagfairSort"; import { RagfairSort } from "@spt/models/enums/RagfairSort";
import { Traders } from "@spt/models/enums/Traders"; import { Traders } from "@spt/models/enums/Traders";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
import { IQuestConfig } from "@spt/models/spt/config/IQuestConfig"; import { IQuestConfig } from "@spt/models/spt/config/IQuestConfig";
import { IRagfairConfig, ITieredFlea } from "@spt/models/spt/config/IRagfairConfig"; import { IRagfairConfig, ITieredFlea } from "@spt/models/spt/config/IRagfairConfig";
import { ILogger } from "@spt/models/spt/utils/ILogger"; import { ILogger } from "@spt/models/spt/utils/ILogger";
@ -42,6 +43,7 @@ export class RagfairOfferHelper {
protected static goodSoldTemplate = "5bdabfb886f7743e152e867e 0"; // Your {soldItem} {itemCount} items were bought by {buyerNickname}. protected static goodSoldTemplate = "5bdabfb886f7743e152e867e 0"; // Your {soldItem} {itemCount} items were bought by {buyerNickname}.
protected ragfairConfig: IRagfairConfig; protected ragfairConfig: IRagfairConfig;
protected questConfig: IQuestConfig; protected questConfig: IQuestConfig;
protected botConfig: IBotConfig;
constructor( constructor(
@inject("PrimaryLogger") protected logger: ILogger, @inject("PrimaryLogger") protected logger: ILogger,
@ -69,6 +71,7 @@ export class RagfairOfferHelper {
) { ) {
this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR); this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR);
this.questConfig = this.configServer.getConfig(ConfigTypes.QUEST); this.questConfig = this.configServer.getConfig(ConfigTypes.QUEST);
this.botConfig = this.configServer.getConfig(ConfigTypes.BOT);
} }
/** /**
@ -565,7 +568,7 @@ export class RagfairOfferHelper {
// Used to replace tokens in sold message sent to player // Used to replace tokens in sold message sent to player
const tplVars: ISystemData = { const tplVars: ISystemData = {
soldItem: globalLocales[`${itemTpl} Name`] || itemTpl, soldItem: globalLocales[`${itemTpl} Name`] || itemTpl,
buyerNickname: this.botHelper.getPmcNicknameOfMaxLength(this.hashUtil.generate(), 15), buyerNickname: this.botHelper.getPmcNicknameOfMaxLength(this.botConfig.botNameLengthLimit),
itemCount: boughtAmount, itemCount: boughtAmount,
}; };

View File

@ -45,6 +45,10 @@ export interface IBotConfig extends IBaseConfig {
/** What bottypes should be excluded from having loot generated on them (backpack/pocket/vest) does not disable food/drink/special/ */ /** What bottypes should be excluded from having loot generated on them (backpack/pocket/vest) does not disable food/drink/special/ */
disableLootOnBotTypes: string[]; disableLootOnBotTypes: string[];
assaultToBossConversion: IAssaultToBossConversion; assaultToBossConversion: IAssaultToBossConversion;
/** Max length a bots name can be */
botNameLengthLimit: number;
/** Bot roles that must have a unique name when generated vs other bots in raid */
botRolesThatMustHaveUniqueName: string[];
} }
export interface IAssaultToBossConversion { export interface IAssaultToBossConversion {

View File

@ -1,4 +1,6 @@
import { BotHelper } from "@spt/helpers/BotHelper";
import { ProfileHelper } from "@spt/helpers/ProfileHelper"; import { ProfileHelper } from "@spt/helpers/ProfileHelper";
import { IBotType } from "@spt/models/eft/common/tables/IBotType";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { BotGenerationDetails } from "@spt/models/spt/bots/BotGenerationDetails"; import { BotGenerationDetails } from "@spt/models/spt/bots/BotGenerationDetails";
import { IBotConfig } from "@spt/models/spt/config/IBotConfig"; import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
@ -21,6 +23,7 @@ export class BotNameService {
@inject("PrimaryLogger") protected logger: ILogger, @inject("PrimaryLogger") protected logger: ILogger,
@inject("RandomUtil") protected randomUtil: RandomUtil, @inject("RandomUtil") protected randomUtil: RandomUtil,
@inject("ProfileHelper") protected profileHelper: ProfileHelper, @inject("ProfileHelper") protected profileHelper: ProfileHelper,
@inject("BotHelper") protected botHelper: BotHelper,
@inject("DatabaseService") protected databaseService: DatabaseService, @inject("DatabaseService") protected databaseService: DatabaseService,
@inject("LocalisationService") protected localisationService: LocalisationService, @inject("LocalisationService") protected localisationService: LocalisationService,
@inject("ConfigServer") protected configServer: ConfigServer, @inject("ConfigServer") protected configServer: ConfigServer,
@ -41,8 +44,7 @@ export class BotNameService {
/** /**
* Create a unique bot nickname * Create a unique bot nickname
* @param firstNames FIRST names to choose from * @param botJsonTemplate bot JSON data from db
* @param lastNames OPTIONAL: Names to choose from
* @param botGenerationDetails * @param botGenerationDetails
* @param botRole role of bot e.g. assault * @param botRole role of bot e.g. assault
* @param uniqueRoles Lowercase roles to always make unique * @param uniqueRoles Lowercase roles to always make unique
@ -50,22 +52,24 @@ export class BotNameService {
* @returns Nickname for bot * @returns Nickname for bot
*/ */
public generateUniqueBotNickname( public generateUniqueBotNickname(
firstNames: string[], botJsonTemplate: IBotType,
lastNames: string[],
botGenerationDetails: BotGenerationDetails, botGenerationDetails: BotGenerationDetails,
botRole: string, botRole: string,
uniqueRoles?: string[], uniqueRoles?: string[],
sessionId?: string,
): string { ): string {
const isPmc = botGenerationDetails.isPmc;
const isPlayerScav = botGenerationDetails.isPlayerScav;
const simulateScavName = isPlayerScav ? false : this.shouldSimulatePlayerScavName(botRole);
const showTypeInNickname = this.botConfig.showTypeInNickname && !isPlayerScav;
const roleShouldBeUnique = uniqueRoles.includes(botRole.toLowerCase());
let isUnique = true; let isUnique = true;
let attempts = 0; let attempts = 0;
while (attempts <= 5) { while (attempts <= 5) {
const isPlayerScav = botGenerationDetails.isPlayerScav; // Get bot name with leading/trailing whitespace removed
const simulateScavName = isPlayerScav ? false : this.shouldSimulatePlayerScavName(botRole); let name = isPmc // Explicit handling of PMCs, all other bots will get "first_name last_name"
? this.botHelper.getPmcNicknameOfMaxLength(this.botConfig.botNameLengthLimit, botGenerationDetails.side)
// Get basic name with no whitespace trimmed off sides : `${this.randomUtil.getArrayValue(botJsonTemplate.firstName)} ${this.randomUtil.getArrayValue(botJsonTemplate.lastName) || ""}`;
let name = `${this.randomUtil.getArrayValue(firstNames)} ${this.randomUtil.getArrayValue(lastNames) || ""}`;
name = name.trim(); name = name.trim();
// Simulate bot looking like a player scav with the PMC name in brackets. // Simulate bot looking like a player scav with the PMC name in brackets.
@ -75,7 +79,7 @@ export class BotNameService {
} }
// Config is set to add role to end of bot name // Config is set to add role to end of bot name
if (this.botConfig.showTypeInNickname && !isPlayerScav) { if (showTypeInNickname) {
name += ` ${botRole}`; name += ` ${botRole}`;
} }
@ -86,7 +90,7 @@ export class BotNameService {
} }
// Is this a role that must be unique // Is this a role that must be unique
if (uniqueRoles.includes(botRole.toLowerCase())) { if (roleShouldBeUnique) {
// Check name in cache // Check name in cache
isUnique = !this.usedNameCache.has(name); isUnique = !this.usedNameCache.has(name);
if (!isUnique) { if (!isUnique) {