Formatting
Have you been using the recommended VSCode extensions? ;)
This commit is contained in:
parent
8227e06d77
commit
90492f3aa2
@ -20,22 +20,27 @@ export class AchievementCallbacks
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle client/achievement/list
|
* Handle client/achievement/list
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
public getAchievements(url: string, info: IEmptyRequestData, sessionID: string): IGetBodyResponseData<IGetAchievementsResponse>
|
public getAchievements(
|
||||||
|
url: string,
|
||||||
|
info: IEmptyRequestData,
|
||||||
|
sessionID: string,
|
||||||
|
): IGetBodyResponseData<IGetAchievementsResponse>
|
||||||
{
|
{
|
||||||
|
|
||||||
return this.httpResponse.getBody(this.achievementController.getAchievements(sessionID));
|
return this.httpResponse.getBody(this.achievementController.getAchievements(sessionID));
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle client/achievement/statistic
|
* Handle client/achievement/statistic
|
||||||
*
|
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
public statistic(url: string, info: IEmptyRequestData, sessionID: string): IGetBodyResponseData<ICompletedAchievementsResponse>
|
public statistic(
|
||||||
|
url: string,
|
||||||
|
info: IEmptyRequestData,
|
||||||
|
sessionID: string,
|
||||||
|
): IGetBodyResponseData<ICompletedAchievementsResponse>
|
||||||
{
|
{
|
||||||
return this.httpResponse.getBody(this.achievementController.getAchievementStatistics(sessionID));
|
return this.httpResponse.getBody(this.achievementController.getAchievementStatistics(sessionID));
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -33,7 +33,7 @@ export class BuildsCallbacks
|
|||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
public createMagazineTemplate(url: string, request: ISetMagazineRequest, sessionID: string): INullResponseData
|
public createMagazineTemplate(url: string, request: ISetMagazineRequest, sessionID: string): INullResponseData
|
||||||
{
|
{
|
||||||
this.buildController.createMagazineTemplate(sessionID, request)
|
this.buildController.createMagazineTemplate(sessionID, request);
|
||||||
|
|
||||||
return this.httpResponse.nullResponse();
|
return this.httpResponse.nullResponse();
|
||||||
}
|
}
|
||||||
|
@ -28,10 +28,7 @@ export class CustomizationCallbacks
|
|||||||
*/
|
*/
|
||||||
public getSuits(url: string, info: IEmptyRequestData, sessionID: string): IGetBodyResponseData<IGetSuitsResponse>
|
public getSuits(url: string, info: IEmptyRequestData, sessionID: string): IGetBodyResponseData<IGetSuitsResponse>
|
||||||
{
|
{
|
||||||
const result: IGetSuitsResponse = {
|
const result: IGetSuitsResponse = { _id: sessionID, suites: this.saveServer.getProfile(sessionID).suits };
|
||||||
_id: sessionID,
|
|
||||||
suites: this.saveServer.getProfile(sessionID).suits,
|
|
||||||
};
|
|
||||||
return this.httpResponse.getBody(result);
|
return this.httpResponse.getBody(result);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -150,7 +150,7 @@ export class GameCallbacks implements OnLoad
|
|||||||
return this.httpResponse.nullResponse();
|
return this.httpResponse.nullResponse();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle singleplayer/settings/getRaidTime
|
* Handle singleplayer/settings/getRaidTime
|
||||||
* @returns string
|
* @returns string
|
||||||
*/
|
*/
|
||||||
|
@ -97,7 +97,7 @@ export class InraidCallbacks
|
|||||||
*/
|
*/
|
||||||
public getTraderServices(url: string, info: IEmptyRequestData, sessionId: string): string
|
public getTraderServices(url: string, info: IEmptyRequestData, sessionId: string): string
|
||||||
{
|
{
|
||||||
const lastSlashPos = url.lastIndexOf('/');
|
const lastSlashPos = url.lastIndexOf("/");
|
||||||
const traderId = url.substring(lastSlashPos + 1);
|
const traderId = url.substring(lastSlashPos + 1);
|
||||||
return this.httpResponse.noBody(this.inraidController.getTraderServices(sessionId, traderId));
|
return this.httpResponse.noBody(this.inraidController.getTraderServices(sessionId, traderId));
|
||||||
}
|
}
|
||||||
|
@ -30,7 +30,7 @@ export class InventoryCallbacks
|
|||||||
{
|
{
|
||||||
constructor(
|
constructor(
|
||||||
@inject("InventoryController") protected inventoryController: InventoryController,
|
@inject("InventoryController") protected inventoryController: InventoryController,
|
||||||
@inject("QuestController") protected questController: QuestController
|
@inject("QuestController") protected questController: QuestController,
|
||||||
)
|
)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -164,17 +164,16 @@ export class InventoryCallbacks
|
|||||||
return this.inventoryController.openRandomLootContainer(pmcData, body, sessionID);
|
return this.inventoryController.openRandomLootContainer(pmcData, body, sessionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
public redeemProfileReward(pmcData: IPmcData,
|
public redeemProfileReward(
|
||||||
|
pmcData: IPmcData,
|
||||||
body: IRedeemProfileRequestData,
|
body: IRedeemProfileRequestData,
|
||||||
sessionId: string
|
sessionId: string,
|
||||||
): IItemEventRouterResponse
|
): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
return this.inventoryController.redeemProfileReward(pmcData, body, sessionId)
|
return this.inventoryController.redeemProfileReward(pmcData, body, sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
public setFavoriteItem(pmcData: IPmcData,
|
public setFavoriteItem(pmcData: IPmcData, body: ISetFavoriteItems, sessionId: string): IItemEventRouterResponse
|
||||||
body: ISetFavoriteItems,
|
|
||||||
sessionId: string): IItemEventRouterResponse
|
|
||||||
{
|
{
|
||||||
return this.inventoryController.setFavoriteItem(pmcData, body, sessionId);
|
return this.inventoryController.setFavoriteItem(pmcData, body, sessionId);
|
||||||
}
|
}
|
||||||
|
@ -160,7 +160,11 @@ export class MatchCallbacks
|
|||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
// eslint-disable-next-line @typescript-eslint/no-unused-vars
|
||||||
public getGroupStatus(url: string, info: IGetGroupStatusRequestData, sessionID: string): IGetBodyResponseData<IGetGroupStatusResponse>
|
public getGroupStatus(
|
||||||
|
url: string,
|
||||||
|
info: IGetGroupStatusRequestData,
|
||||||
|
sessionID: string,
|
||||||
|
): IGetBodyResponseData<IGetGroupStatusResponse>
|
||||||
{
|
{
|
||||||
return this.httpResponse.getBody(this.matchController.getGroupStatus(info));
|
return this.httpResponse.getBody(this.matchController.getGroupStatus(info));
|
||||||
}
|
}
|
||||||
|
@ -34,7 +34,11 @@ export class ProfileCallbacks
|
|||||||
/**
|
/**
|
||||||
* Handle client/game/profile/create
|
* Handle client/game/profile/create
|
||||||
*/
|
*/
|
||||||
public createProfile(url: string, info: IProfileCreateRequestData, sessionID: string): IGetBodyResponseData<ICreateProfileResponse>
|
public createProfile(
|
||||||
|
url: string,
|
||||||
|
info: IProfileCreateRequestData,
|
||||||
|
sessionID: string,
|
||||||
|
): IGetBodyResponseData<ICreateProfileResponse>
|
||||||
{
|
{
|
||||||
const id = this.profileController.createProfile(info, sessionID);
|
const id = this.profileController.createProfile(info, sessionID);
|
||||||
|
|
||||||
|
@ -69,7 +69,7 @@ export class RagfairCallbacks implements OnLoad, OnUpdate
|
|||||||
|
|
||||||
// Process all offers / expire offers
|
// Process all offers / expire offers
|
||||||
await this.ragfairServer.update();
|
await this.ragfairServer.update();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
@ -142,7 +142,11 @@ export class RagfairCallbacks implements OnLoad, OnUpdate
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Handle client/ragfair/offer/findbyid */
|
/** Handle client/ragfair/offer/findbyid */
|
||||||
public getFleaOfferById(url: string, request: IGetRagfairOfferByIdRequest, sessionID: string): IGetBodyResponseData<IRagfairOffer>
|
public getFleaOfferById(
|
||||||
|
url: string,
|
||||||
|
request: IGetRagfairOfferByIdRequest,
|
||||||
|
sessionID: string,
|
||||||
|
): IGetBodyResponseData<IRagfairOffer>
|
||||||
{
|
{
|
||||||
return this.httpResponse.getBody(this.ragfairController.getOfferById(sessionID, request));
|
return this.httpResponse.getBody(this.ragfairController.getOfferById(sessionID, request));
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export enum ContextVariableType {
|
export enum ContextVariableType
|
||||||
|
{
|
||||||
/** Logged in users session id */
|
/** Logged in users session id */
|
||||||
SESSION_ID = 0,
|
SESSION_ID = 0,
|
||||||
/** Currently acive raid information */
|
/** Currently acive raid information */
|
||||||
|
@ -23,7 +23,7 @@ export class AchievementController
|
|||||||
*/
|
*/
|
||||||
public getAchievements(sessionID: string): IGetAchievementsResponse
|
public getAchievements(sessionID: string): IGetAchievementsResponse
|
||||||
{
|
{
|
||||||
return {elements: this.databaseServer.getTables().templates.achievements };
|
return { elements: this.databaseServer.getTables().templates.achievements };
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -34,13 +34,13 @@ export class AchievementController
|
|||||||
public getAchievementStatistics(sessionId: string): ICompletedAchievementsResponse
|
public getAchievementStatistics(sessionId: string): ICompletedAchievementsResponse
|
||||||
{
|
{
|
||||||
const achievements = this.databaseServer.getTables().templates.achievements;
|
const achievements = this.databaseServer.getTables().templates.achievements;
|
||||||
const stats = {}
|
const stats = {};
|
||||||
|
|
||||||
for (const achievement of achievements)
|
for (const achievement of achievements)
|
||||||
{
|
{
|
||||||
stats[achievement.id] = 0;
|
stats[achievement.id] = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
return {elements: stats};
|
return { elements: stats };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -153,7 +153,7 @@ export class BotController
|
|||||||
{
|
{
|
||||||
return this.generateBotsFirstTime(info, pmcProfile, sessionId);
|
return this.generateBotsFirstTime(info, pmcProfile, sessionId);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.returnSingleBotFromCache(sessionId, info);
|
return this.returnSingleBotFromCache(sessionId, info);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -162,11 +162,17 @@ export class BotController
|
|||||||
* @param request Bot generation request object
|
* @param request Bot generation request object
|
||||||
* @param pmcProfile Player profile
|
* @param pmcProfile Player profile
|
||||||
* @param sessionId Session id
|
* @param sessionId Session id
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
protected generateBotsFirstTime(request: IGenerateBotsRequestData, pmcProfile: IPmcData, sessionId: string): IBotBase[]
|
protected generateBotsFirstTime(
|
||||||
|
request: IGenerateBotsRequestData,
|
||||||
|
pmcProfile: IPmcData,
|
||||||
|
sessionId: string,
|
||||||
|
): IBotBase[]
|
||||||
{
|
{
|
||||||
const allPmcsHaveSameNameAsPlayer = this.randomUtil.getChance100(this.pmcConfig.allPMCsHavePlayerNameWithRandomPrefixChance);
|
const allPmcsHaveSameNameAsPlayer = this.randomUtil.getChance100(
|
||||||
|
this.pmcConfig.allPMCsHavePlayerNameWithRandomPrefixChance,
|
||||||
|
);
|
||||||
for (const condition of request.conditions)
|
for (const condition of request.conditions)
|
||||||
{
|
{
|
||||||
const botGenerationDetails: BotGenerationDetails = {
|
const botGenerationDetails: BotGenerationDetails = {
|
||||||
@ -180,7 +186,7 @@ export class BotController
|
|||||||
botCountToGenerate: this.botConfig.presetBatch[condition.Role],
|
botCountToGenerate: this.botConfig.presetBatch[condition.Role],
|
||||||
botDifficulty: condition.Difficulty,
|
botDifficulty: condition.Difficulty,
|
||||||
isPlayerScav: false,
|
isPlayerScav: false,
|
||||||
allPmcsHaveSameNameAsPlayer: allPmcsHaveSameNameAsPlayer
|
allPmcsHaveSameNameAsPlayer: allPmcsHaveSameNameAsPlayer,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Event bots need special actions to occur, set data up for them
|
// Event bots need special actions to occur, set data up for them
|
||||||
@ -190,7 +196,7 @@ export class BotController
|
|||||||
// Add eventRole data + reassign role property to be base type
|
// Add eventRole data + reassign role property to be base type
|
||||||
botGenerationDetails.eventRole = condition.Role;
|
botGenerationDetails.eventRole = condition.Role;
|
||||||
botGenerationDetails.role = this.seasonalEventService.getBaseRoleForEventBot(
|
botGenerationDetails.role = this.seasonalEventService.getBaseRoleForEventBot(
|
||||||
botGenerationDetails.eventRole
|
botGenerationDetails.eventRole,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -338,9 +344,9 @@ export class BotController
|
|||||||
public getBotCap(): number
|
public getBotCap(): number
|
||||||
{
|
{
|
||||||
const defaultMapCapId = "default";
|
const defaultMapCapId = "default";
|
||||||
const raidConfig = this.applicationContext
|
const raidConfig = this.applicationContext.getLatestValue(ContextVariableType.RAID_CONFIGURATION).getValue<
|
||||||
.getLatestValue(ContextVariableType.RAID_CONFIGURATION)
|
IGetRaidConfigurationRequestData
|
||||||
.getValue<IGetRaidConfigurationRequestData>();
|
>();
|
||||||
|
|
||||||
if (!raidConfig)
|
if (!raidConfig)
|
||||||
{
|
{
|
||||||
@ -366,9 +372,10 @@ export class BotController
|
|||||||
|
|
||||||
public getAiBotBrainTypes(): any
|
public getAiBotBrainTypes(): any
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
pmc: this.pmcConfig.pmcType,
|
pmc: this.pmcConfig.pmcType,
|
||||||
assault: this.botConfig.assaultBrainType,
|
assault: this.botConfig.assaultBrainType,
|
||||||
playerScav: this.botConfig.playerScavBrainType};
|
playerScav: this.botConfig.playerScavBrainType,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -71,10 +71,7 @@ export class BuildController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Handle client/builds/weapon/save */
|
/** Handle client/builds/weapon/save */
|
||||||
public saveWeaponBuild(
|
public saveWeaponBuild(sessionId: string, body: IPresetBuildActionRequestData): void
|
||||||
sessionId: string,
|
|
||||||
body: IPresetBuildActionRequestData,
|
|
||||||
): void
|
|
||||||
{
|
{
|
||||||
const pmcData = this.profileHelper.getPmcProfile(sessionId);
|
const pmcData = this.profileHelper.getPmcProfile(sessionId);
|
||||||
|
|
||||||
@ -84,12 +81,7 @@ export class BuildController
|
|||||||
body.Root = body.Items[0]._id;
|
body.Root = body.Items[0]._id;
|
||||||
|
|
||||||
// Create new object ready to save into profile userbuilds.weaponBuilds
|
// Create new object ready to save into profile userbuilds.weaponBuilds
|
||||||
const newBuild: IWeaponBuild = {
|
const newBuild: IWeaponBuild = { Id: body.Id, Name: body.Name, Root: body.Root, Items: body.Items };
|
||||||
Id: body.Id,
|
|
||||||
Name: body.Name,
|
|
||||||
Root: body.Root,
|
|
||||||
Items: body.Items,
|
|
||||||
};
|
|
||||||
|
|
||||||
const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds;
|
const savedWeaponBuilds = this.saveServer.getProfile(sessionId).userbuilds.weaponBuilds;
|
||||||
const existingBuild = savedWeaponBuilds.find((x) => x.Id === body.Id);
|
const existingBuild = savedWeaponBuilds.find((x) => x.Id === body.Id);
|
||||||
@ -110,15 +102,13 @@ export class BuildController
|
|||||||
}
|
}
|
||||||
|
|
||||||
/** Handle client/builds/equipment/save event */
|
/** Handle client/builds/equipment/save event */
|
||||||
public saveEquipmentBuild(
|
public saveEquipmentBuild(sessionID: string, request: IPresetBuildActionRequestData): void
|
||||||
sessionID: string,
|
|
||||||
request: IPresetBuildActionRequestData,
|
|
||||||
): void
|
|
||||||
{
|
{
|
||||||
const buildType = "equipmentBuilds";
|
const buildType = "equipmentBuilds";
|
||||||
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
const pmcData = this.profileHelper.getPmcProfile(sessionID);
|
||||||
|
|
||||||
const existingSavedEquipmentBuilds: IEquipmentBuild[] = this.saveServer.getProfile(sessionID).userbuilds[buildType];
|
const existingSavedEquipmentBuilds: IEquipmentBuild[] =
|
||||||
|
this.saveServer.getProfile(sessionID).userbuilds[buildType];
|
||||||
|
|
||||||
// Replace duplicate ID's. The first item is the base item.
|
// Replace duplicate ID's. The first item is the base item.
|
||||||
// Root ID and the base item ID need to match.
|
// Root ID and the base item ID need to match.
|
||||||
@ -214,16 +204,15 @@ export class BuildController
|
|||||||
profile.userbuilds.magazineBuilds = [];
|
profile.userbuilds.magazineBuilds = [];
|
||||||
}
|
}
|
||||||
|
|
||||||
const existingArrayId = profile.userbuilds.magazineBuilds.findIndex(item => item.Name === request.Name);
|
const existingArrayId = profile.userbuilds.magazineBuilds.findIndex((item) => item.Name === request.Name);
|
||||||
|
|
||||||
if (existingArrayId === -1)
|
if (existingArrayId === -1)
|
||||||
{
|
{
|
||||||
|
|
||||||
profile.userbuilds.magazineBuilds.push(result);
|
profile.userbuilds.magazineBuilds.push(result);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
profile.userbuilds.magazineBuilds.splice(existingArrayId, 1, result)
|
profile.userbuilds.magazineBuilds.splice(existingArrayId, 1, result);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -131,7 +131,7 @@ export class GameController
|
|||||||
|
|
||||||
this.checkTraderRepairValuesExist();
|
this.checkTraderRepairValuesExist();
|
||||||
|
|
||||||
this.adjustLocationBotValues()
|
this.adjustLocationBotValues();
|
||||||
|
|
||||||
// repeatableQuests are stored by in profile.Quests due to the responses of the client (e.g. Quests in
|
// repeatableQuests are stored by in profile.Quests due to the responses of the client (e.g. Quests in
|
||||||
// offraidData). Since we don't want to clutter the Quests list, we need to remove all completed (failed or
|
// offraidData). Since we don't want to clutter the Quests list, we need to remove all completed (failed or
|
||||||
@ -151,7 +151,7 @@ export class GameController
|
|||||||
|
|
||||||
if (this.coreConfig.fixes.fixProfileBreakingInventoryItemIssues)
|
if (this.coreConfig.fixes.fixProfileBreakingInventoryItemIssues)
|
||||||
{
|
{
|
||||||
this.profileFixerService.fixProfileBreakingInventoryItemIssues(pmcProfile)
|
this.profileFixerService.fixProfileBreakingInventoryItemIssues(pmcProfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (pmcProfile.Health)
|
if (pmcProfile.Health)
|
||||||
@ -439,7 +439,10 @@ export class GameController
|
|||||||
public getGameConfig(sessionID: string): IGameConfigResponse
|
public getGameConfig(sessionID: string): IGameConfigResponse
|
||||||
{
|
{
|
||||||
const profile = this.profileHelper.getPmcProfile(sessionID);
|
const profile = this.profileHelper.getPmcProfile(sessionID);
|
||||||
const gameTime = profile.Stats?.Eft.OverallCounters.Items?.find(counter => counter.Key.includes("LifeTime") && counter.Key.includes("Pmc"))?.Value ?? 0;
|
const gameTime =
|
||||||
|
profile.Stats?.Eft.OverallCounters.Items?.find((counter) =>
|
||||||
|
counter.Key.includes("LifeTime") && counter.Key.includes("Pmc")
|
||||||
|
)?.Value ?? 0;
|
||||||
|
|
||||||
const config: IGameConfigResponse = {
|
const config: IGameConfigResponse = {
|
||||||
languages: this.databaseServer.getTables().locales.languages,
|
languages: this.databaseServer.getTables().locales.languages,
|
||||||
@ -574,10 +577,8 @@ export class GameController
|
|||||||
(sum, curr) => sum + curr.value,
|
(sum, curr) => sum + curr.value,
|
||||||
0,
|
0,
|
||||||
);
|
);
|
||||||
hydrationRegenPerHour += pmcProfile.Bonuses.filter((x) => x.type === BonusType.HYDRATION_REGENERATION).reduce(
|
hydrationRegenPerHour += pmcProfile.Bonuses.filter((x) => x.type === BonusType.HYDRATION_REGENERATION)
|
||||||
(sum, curr) => sum + curr.value,
|
.reduce((sum, curr) => sum + curr.value, 0);
|
||||||
0,
|
|
||||||
);
|
|
||||||
hpRegenPerHour += pmcProfile.Bonuses.filter((x) => x.type === BonusType.HEALTH_REGENERATION).reduce(
|
hpRegenPerHour += pmcProfile.Bonuses.filter((x) => x.type === BonusType.HEALTH_REGENERATION).reduce(
|
||||||
(sum, curr) => sum + curr.value,
|
(sum, curr) => sum + curr.value,
|
||||||
0,
|
0,
|
||||||
@ -822,7 +823,7 @@ export class GameController
|
|||||||
dateAdded: Date.now(),
|
dateAdded: Date.now(),
|
||||||
name: modDetails.name,
|
name: modDetails.name,
|
||||||
version: modDetails.version,
|
version: modDetails.version,
|
||||||
url: modDetails.url
|
url: modDetails.url,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -8,7 +8,13 @@ import { PaymentHelper } from "@spt-aki/helpers/PaymentHelper";
|
|||||||
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
import { PresetHelper } from "@spt-aki/helpers/PresetHelper";
|
||||||
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
import { ProfileHelper } from "@spt-aki/helpers/ProfileHelper";
|
||||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||||
import { HideoutArea, ITaskConditionCounter, Product, Production, ScavCase } from "@spt-aki/models/eft/common/tables/IBotBase";
|
import {
|
||||||
|
HideoutArea,
|
||||||
|
ITaskConditionCounter,
|
||||||
|
Product,
|
||||||
|
Production,
|
||||||
|
ScavCase,
|
||||||
|
} from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||||
import { HideoutUpgradeCompleteRequestData } from "@spt-aki/models/eft/hideout/HideoutUpgradeCompleteRequestData";
|
import { HideoutUpgradeCompleteRequestData } from "@spt-aki/models/eft/hideout/HideoutUpgradeCompleteRequestData";
|
||||||
import { IHandleQTEEventRequestData } from "@spt-aki/models/eft/hideout/IHandleQTEEventRequestData";
|
import { IHandleQTEEventRequestData } from "@spt-aki/models/eft/hideout/IHandleQTEEventRequestData";
|
||||||
@ -503,9 +509,9 @@ export class HideoutController
|
|||||||
itemWithModsToAdd: [itemToReturn],
|
itemWithModsToAdd: [itemToReturn],
|
||||||
foundInRaid: !!itemToReturn.upd.SpawnedInSession,
|
foundInRaid: !!itemToReturn.upd.SpawnedInSession,
|
||||||
callback: null,
|
callback: null,
|
||||||
useSortingTable: false
|
useSortingTable: false,
|
||||||
}
|
};
|
||||||
|
|
||||||
this.inventoryHelper.addItemToStash(sessionID, request, pmcData, output);
|
this.inventoryHelper.addItemToStash(sessionID, request, pmcData, output);
|
||||||
if (output.warnings && output.warnings.length > 0)
|
if (output.warnings && output.warnings.length > 0)
|
||||||
{
|
{
|
||||||
@ -787,10 +793,7 @@ export class HideoutController
|
|||||||
const preset = this.presetHelper.getDefaultPreset(recipe.endProduct);
|
const preset = this.presetHelper.getDefaultPreset(recipe.endProduct);
|
||||||
|
|
||||||
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
|
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
|
||||||
const presetAndMods: Item[] = this.itemHelper.replaceIDs(
|
const presetAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(preset._items));
|
||||||
null,
|
|
||||||
this.jsonUtil.clone(preset._items),
|
|
||||||
);
|
|
||||||
|
|
||||||
this.itemHelper.remapRootItemId(presetAndMods);
|
this.itemHelper.remapRootItemId(presetAndMods);
|
||||||
|
|
||||||
@ -805,9 +808,7 @@ export class HideoutController
|
|||||||
const rewardToAdd: Item = {
|
const rewardToAdd: Item = {
|
||||||
_id: this.hashUtil.generate(),
|
_id: this.hashUtil.generate(),
|
||||||
_tpl: recipe.endProduct,
|
_tpl: recipe.endProduct,
|
||||||
upd: {
|
upd: { StackObjectsCount: recipe.count },
|
||||||
StackObjectsCount: recipe.count
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
|
|
||||||
// Split item into separate items with acceptable stack sizes
|
// Split item into separate items with acceptable stack sizes
|
||||||
@ -821,10 +822,7 @@ export class HideoutController
|
|||||||
// Add the first reward item to array when not a preset (first preset added above earlier)
|
// Add the first reward item to array when not a preset (first preset added above earlier)
|
||||||
if (!rewardIsPreset)
|
if (!rewardIsPreset)
|
||||||
{
|
{
|
||||||
itemAndChildrenToSendToPlayer.push([{
|
itemAndChildrenToSendToPlayer.push([{ _id: this.hashUtil.generate(), _tpl: recipe.endProduct }]);
|
||||||
_id: this.hashUtil.generate(),
|
|
||||||
_tpl: recipe.endProduct
|
|
||||||
}]);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Add multiple of item if recipe requests it
|
// Add multiple of item if recipe requests it
|
||||||
@ -846,10 +844,9 @@ export class HideoutController
|
|||||||
{
|
{
|
||||||
for (const reward of itemAndChildrenToSendToPlayer)
|
for (const reward of itemAndChildrenToSendToPlayer)
|
||||||
{
|
{
|
||||||
|
|
||||||
if (!reward[0].upd)
|
if (!reward[0].upd)
|
||||||
{
|
{
|
||||||
reward[0].upd = {}
|
reward[0].upd = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
reward[0].upd.RecodableComponent = { IsEncoded: true };
|
reward[0].upd.RecodableComponent = { IsEncoded: true };
|
||||||
@ -916,7 +913,7 @@ export class HideoutController
|
|||||||
itemsWithModsToAdd: itemAndChildrenToSendToPlayer,
|
itemsWithModsToAdd: itemAndChildrenToSendToPlayer,
|
||||||
foundInRaid: true,
|
foundInRaid: true,
|
||||||
useSortingTable: false,
|
useSortingTable: false,
|
||||||
callback: null
|
callback: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add FiR crafted items(s) to player inventory
|
// Add FiR crafted items(s) to player inventory
|
||||||
@ -946,13 +943,8 @@ export class HideoutController
|
|||||||
const intellectAmountToGive = 0.5 * (Math.round(craftingExpAmount / 15));
|
const intellectAmountToGive = 0.5 * (Math.round(craftingExpAmount / 15));
|
||||||
if (intellectAmountToGive > 0)
|
if (intellectAmountToGive > 0)
|
||||||
{
|
{
|
||||||
this.profileHelper.addSkillPointsToPlayer(
|
this.profileHelper.addSkillPointsToPlayer(pmcData, SkillTypes.INTELLECT, intellectAmountToGive);
|
||||||
pmcData,
|
|
||||||
SkillTypes.INTELLECT,
|
|
||||||
intellectAmountToGive,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
area.lastRecipe = request.recipeId;
|
area.lastRecipe = request.recipeId;
|
||||||
|
|
||||||
@ -1042,7 +1034,7 @@ export class HideoutController
|
|||||||
itemsWithModsToAdd: scavCaseRewards,
|
itemsWithModsToAdd: scavCaseRewards,
|
||||||
foundInRaid: true,
|
foundInRaid: true,
|
||||||
callback: null,
|
callback: null,
|
||||||
useSortingTable: false
|
useSortingTable: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
this.inventoryHelper.addItemsToStash(sessionID, addItemsRequest, pmcData, output);
|
this.inventoryHelper.addItemsToStash(sessionID, addItemsRequest, pmcData, output);
|
||||||
|
@ -348,7 +348,7 @@ export class InraidController
|
|||||||
{
|
{
|
||||||
for (const quest of scavProfile.Quests)
|
for (const quest of scavProfile.Quests)
|
||||||
{
|
{
|
||||||
const pmcQuest = pmcProfile.Quests.find(x => x.qid === quest.qid);
|
const pmcQuest = pmcProfile.Quests.find((x) => x.qid === quest.qid);
|
||||||
if (!pmcQuest)
|
if (!pmcQuest)
|
||||||
{
|
{
|
||||||
this.logger.warning(`No PMC quest found for ID: ${quest.qid}`);
|
this.logger.warning(`No PMC quest found for ID: ${quest.qid}`);
|
||||||
@ -546,9 +546,9 @@ export class InraidController
|
|||||||
|
|
||||||
// Remove any items that were returned by the item delivery, but also insured, from the player's insurance list
|
// Remove any items that were returned by the item delivery, but also insured, from the player's insurance list
|
||||||
// This is to stop items being duplicated by being returned from both the item delivery, and insurance
|
// This is to stop items being duplicated by being returned from both the item delivery, and insurance
|
||||||
const deliveredItemIds = items.map(x => x._id);
|
const deliveredItemIds = items.map((x) => x._id);
|
||||||
pmcData.InsuredItems = pmcData.InsuredItems.filter(x => !deliveredItemIds.includes(x.itemId));
|
pmcData.InsuredItems = pmcData.InsuredItems.filter((x) => !deliveredItemIds.includes(x.itemId));
|
||||||
|
|
||||||
// Send the items to the player
|
// Send the items to the player
|
||||||
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
||||||
sessionId,
|
sessionId,
|
||||||
|
@ -121,8 +121,7 @@ export class InventoryController
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Item is moving into or out of place of fame dogtag slot
|
// Item is moving into or out of place of fame dogtag slot
|
||||||
if (moveRequest.to.container.startsWith("dogtag")
|
if (moveRequest.to.container.startsWith("dogtag") || originalLocationSlotId.startsWith("dogtag"))
|
||||||
|| originalLocationSlotId.startsWith("dogtag"))
|
|
||||||
{
|
{
|
||||||
this.hideoutHelper.applyPlaceOfFameDogtagBonus(pmcData);
|
this.hideoutHelper.applyPlaceOfFameDogtagBonus(pmcData);
|
||||||
}
|
}
|
||||||
@ -177,11 +176,7 @@ export class InventoryController
|
|||||||
|
|
||||||
if (body.fromOwner?.type === "Mail")
|
if (body.fromOwner?.type === "Mail")
|
||||||
{
|
{
|
||||||
this.inventoryHelper.removeItemAndChildrenFromMailRewards(
|
this.inventoryHelper.removeItemAndChildrenFromMailRewards(sessionID, body, output);
|
||||||
sessionID,
|
|
||||||
body,
|
|
||||||
output,
|
|
||||||
);
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -190,12 +185,7 @@ export class InventoryController
|
|||||||
? pmcData
|
? pmcData
|
||||||
: this.profileHelper.getFullProfile(sessionID).characters.scav;
|
: this.profileHelper.getFullProfile(sessionID).characters.scav;
|
||||||
|
|
||||||
return this.inventoryHelper.removeItem(
|
return this.inventoryHelper.removeItem(profileToRemoveItemFrom, body.item, sessionID, output);
|
||||||
profileToRemoveItemFrom,
|
|
||||||
body.item,
|
|
||||||
sessionID,
|
|
||||||
output,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -527,9 +517,7 @@ export class InventoryController
|
|||||||
return this.eventOutputHolder.getOutput(sessionID);
|
return this.eventOutputHolder.getOutput(sessionID);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.warning(
|
this.logger.warning(this.localisationService.getText("inventory-unable_to_toggle_item_not_found", body.item));
|
||||||
this.localisationService.getText("inventory-unable_to_toggle_item_not_found", body.item),
|
|
||||||
);
|
|
||||||
|
|
||||||
return { warnings: [], profileChanges: {} };
|
return { warnings: [], profileChanges: {} };
|
||||||
}
|
}
|
||||||
@ -685,7 +673,7 @@ export class InventoryController
|
|||||||
const item = this.databaseServer.getTables().templates.items[itemTpl];
|
const item = this.databaseServer.getTables().templates.items[itemTpl];
|
||||||
if (!item)
|
if (!item)
|
||||||
{
|
{
|
||||||
this.logger.warning(`Unable to find item with id ${itemTpl}, skipping inspection`)
|
this.logger.warning(`Unable to find item with id ${itemTpl}, skipping inspection`);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -932,7 +920,7 @@ export class InventoryController
|
|||||||
|
|
||||||
if (containerSettings.foundInRaid)
|
if (containerSettings.foundInRaid)
|
||||||
{
|
{
|
||||||
foundInRaid = containerSettings.foundInRaid
|
foundInRaid = containerSettings.foundInRaid;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -950,8 +938,8 @@ export class InventoryController
|
|||||||
itemsWithModsToAdd: rewards,
|
itemsWithModsToAdd: rewards,
|
||||||
foundInRaid: foundInRaid,
|
foundInRaid: foundInRaid,
|
||||||
callback: null,
|
callback: null,
|
||||||
useSortingTable: true
|
useSortingTable: true,
|
||||||
}
|
};
|
||||||
this.inventoryHelper.addItemsToStash(sessionID, addItemsRequest, pmcData, output);
|
this.inventoryHelper.addItemsToStash(sessionID, addItemsRequest, pmcData, output);
|
||||||
if (output.warnings.length > 0)
|
if (output.warnings.length > 0)
|
||||||
{
|
{
|
||||||
@ -964,7 +952,11 @@ export class InventoryController
|
|||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
|
||||||
public redeemProfileReward(pmcData: IPmcData, request: IRedeemProfileRequestData, sessionId: string): IItemEventRouterResponse
|
public redeemProfileReward(
|
||||||
|
pmcData: IPmcData,
|
||||||
|
request: IRedeemProfileRequestData,
|
||||||
|
sessionId: string,
|
||||||
|
): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
const output = this.eventOutputHolder.getOutput(sessionId);
|
const output = this.eventOutputHolder.getOutput(sessionId);
|
||||||
|
|
||||||
@ -974,8 +966,8 @@ export class InventoryController
|
|||||||
// Hard coded to `SYSTEM` for now
|
// Hard coded to `SYSTEM` for now
|
||||||
// TODO: make this dynamic
|
// TODO: make this dynamic
|
||||||
const dialog = fullprofile.dialogues["59e7125688a45068a6249071"];
|
const dialog = fullprofile.dialogues["59e7125688a45068a6249071"];
|
||||||
const mail = dialog.messages.find(x => x._id === event.MessageId);
|
const mail = dialog.messages.find((x) => x._id === event.MessageId);
|
||||||
const mailEvent = mail.profileChangeEvents.find(x => x._id === event.EventId);
|
const mailEvent = mail.profileChangeEvents.find((x) => x._id === event.EventId);
|
||||||
|
|
||||||
switch (mailEvent.Type)
|
switch (mailEvent.Type)
|
||||||
{
|
{
|
||||||
@ -994,15 +986,15 @@ export class InventoryController
|
|||||||
break;
|
break;
|
||||||
case "SkillPoints":
|
case "SkillPoints":
|
||||||
{
|
{
|
||||||
const profileSkill = pmcData.Skills.Common.find(x => x.Id === mailEvent.entity);
|
const profileSkill = pmcData.Skills.Common.find((x) => x.Id === mailEvent.entity);
|
||||||
profileSkill.Progress = mailEvent.value;
|
profileSkill.Progress = mailEvent.value;
|
||||||
this.logger.success(`Set profile skill: ${mailEvent.entity} to: ${mailEvent.value}`);
|
this.logger.success(`Set profile skill: ${mailEvent.entity} to: ${mailEvent.value}`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
case "ExamineAllItems":
|
case "ExamineAllItems":
|
||||||
{
|
{
|
||||||
const itemsToInspect = this.itemHelper.getItems().filter(x => x._type !== "Node");
|
const itemsToInspect = this.itemHelper.getItems().filter((x) => x._type !== "Node");
|
||||||
this.flagItemsAsInspectedAndRewardXp(itemsToInspect.map(x => x._id), pmcData);
|
this.flagItemsAsInspectedAndRewardXp(itemsToInspect.map((x) => x._id), pmcData);
|
||||||
this.logger.success(`Flagged ${itemsToInspect.length} items as examined`);
|
this.logger.success(`Flagged ${itemsToInspect.length} items as examined`);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -1031,7 +1023,7 @@ export class InventoryController
|
|||||||
for (const itemId of request.items)
|
for (const itemId of request.items)
|
||||||
{
|
{
|
||||||
// If id already exists in array, we're removing it
|
// If id already exists in array, we're removing it
|
||||||
const indexOfItemAlreadyFavorited = pmcData.Inventory.favoriteItems.findIndex(x => x === itemId);
|
const indexOfItemAlreadyFavorited = pmcData.Inventory.favoriteItems.findIndex((x) => x === itemId);
|
||||||
if (indexOfItemAlreadyFavorited > -1)
|
if (indexOfItemAlreadyFavorited > -1)
|
||||||
{
|
{
|
||||||
pmcData.Inventory.favoriteItems.splice(indexOfItemAlreadyFavorited, 1);
|
pmcData.Inventory.favoriteItems.splice(indexOfItemAlreadyFavorited, 1);
|
||||||
@ -1041,7 +1033,7 @@ export class InventoryController
|
|||||||
pmcData.Inventory.favoriteItems.push(itemId);
|
pmcData.Inventory.favoriteItems.push(itemId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -132,7 +132,7 @@ export class LauncherController
|
|||||||
|
|
||||||
return profileId;
|
return profileId;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected generateProfileId(): string
|
protected generateProfileId(): string
|
||||||
{
|
{
|
||||||
const timestamp = this.timeUtil.getTimestamp();
|
const timestamp = this.timeUtil.getTimestamp();
|
||||||
@ -142,8 +142,8 @@ export class LauncherController
|
|||||||
|
|
||||||
protected formatID(timeStamp: number, counter: number): string
|
protected formatID(timeStamp: number, counter: number): string
|
||||||
{
|
{
|
||||||
const timeStampStr = timeStamp.toString(16).padStart(8, '0');
|
const timeStampStr = timeStamp.toString(16).padStart(8, "0");
|
||||||
const counterStr = counter.toString(16).padStart(16, '0');
|
const counterStr = counter.toString(16).padStart(16, "0");
|
||||||
|
|
||||||
return timeStampStr.toLowerCase() + counterStr.toLowerCase();
|
return timeStampStr.toLowerCase() + counterStr.toLowerCase();
|
||||||
}
|
}
|
||||||
|
@ -91,7 +91,9 @@ export class LocationController
|
|||||||
|
|
||||||
// Check for a loot multipler adjustment in app context and apply if one is found
|
// Check for a loot multipler adjustment in app context and apply if one is found
|
||||||
let locationConfigCopy: ILocationConfig;
|
let locationConfigCopy: ILocationConfig;
|
||||||
const raidAdjustments = this.applicationContext.getLatestValue(ContextVariableType.RAID_ADJUSTMENTS)?.getValue<IRaidChanges>();
|
const raidAdjustments = this.applicationContext.getLatestValue(ContextVariableType.RAID_ADJUSTMENTS)?.getValue<
|
||||||
|
IRaidChanges
|
||||||
|
>();
|
||||||
if (raidAdjustments)
|
if (raidAdjustments)
|
||||||
{
|
{
|
||||||
locationConfigCopy = this.jsonUtil.clone(this.locationConfig); // Clone values so they can be used to reset originals later
|
locationConfigCopy = this.jsonUtil.clone(this.locationConfig); // Clone values so they can be used to reset originals later
|
||||||
|
@ -185,7 +185,7 @@ export class ProfileController
|
|||||||
inraid: {} as Inraid,
|
inraid: {} as Inraid,
|
||||||
insurance: [],
|
insurance: [],
|
||||||
traderPurchases: {},
|
traderPurchases: {},
|
||||||
achievements: {}
|
achievements: {},
|
||||||
};
|
};
|
||||||
|
|
||||||
this.profileFixerService.checkForAndFixPmcProfileIssues(profileDetails.characters.pmc);
|
this.profileFixerService.checkForAndFixPmcProfileIssues(profileDetails.characters.pmc);
|
||||||
@ -391,7 +391,7 @@ export class ProfileController
|
|||||||
return [{ _id: this.hashUtil.generate(), Info: { Level: 1, Side: "Bear", Nickname: info.nickname } }];
|
return [{ _id: this.hashUtil.generate(), Info: { Level: 1, Side: "Bear", Nickname: info.nickname } }];
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Handle client/profile/status
|
* Handle client/profile/status
|
||||||
*/
|
*/
|
||||||
public getProfileStatus(sessionId: string): GetProfileStatusResponseData
|
public getProfileStatus(sessionId: string): GetProfileStatusResponseData
|
||||||
@ -399,20 +399,14 @@ export class ProfileController
|
|||||||
const account = this.saveServer.getProfile(sessionId).info;
|
const account = this.saveServer.getProfile(sessionId).info;
|
||||||
const response: GetProfileStatusResponseData = {
|
const response: GetProfileStatusResponseData = {
|
||||||
maxPveCountExceeded: false,
|
maxPveCountExceeded: false,
|
||||||
profiles: [{
|
profiles: [{ profileid: account.scavId, profileToken: null, status: "Free", sid: "", ip: "", port: 0 }, {
|
||||||
profileid: account.scavId,
|
|
||||||
profileToken: null,
|
|
||||||
status: "Free",
|
|
||||||
sid: "",
|
|
||||||
ip: "",
|
|
||||||
port: 0,
|
|
||||||
}, {
|
|
||||||
profileid: account.id,
|
profileid: account.id,
|
||||||
profileToken: null,
|
profileToken: null,
|
||||||
status: "Free",
|
status: "Free",
|
||||||
sid: "",
|
sid: "",
|
||||||
ip: "",
|
ip: "",
|
||||||
port: 0 }],
|
port: 0,
|
||||||
|
}],
|
||||||
};
|
};
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
@ -422,7 +416,7 @@ export class ProfileController
|
|||||||
{
|
{
|
||||||
const player = this.profileHelper.getFullProfile(sessionId);
|
const player = this.profileHelper.getFullProfile(sessionId);
|
||||||
const playerPmc = player.characters.pmc;
|
const playerPmc = player.characters.pmc;
|
||||||
|
|
||||||
// return player for now
|
// return player for now
|
||||||
return {
|
return {
|
||||||
id: playerPmc._id,
|
id: playerPmc._id,
|
||||||
@ -434,34 +428,34 @@ export class ProfileController
|
|||||||
memberCategory: playerPmc.Info.MemberCategory,
|
memberCategory: playerPmc.Info.MemberCategory,
|
||||||
bannedState: playerPmc.Info.BannedState,
|
bannedState: playerPmc.Info.BannedState,
|
||||||
bannedUntil: playerPmc.Info.BannedUntil,
|
bannedUntil: playerPmc.Info.BannedUntil,
|
||||||
registrationDate: playerPmc.Info.RegistrationDate
|
registrationDate: playerPmc.Info.RegistrationDate,
|
||||||
},
|
},
|
||||||
customization: {
|
customization: {
|
||||||
head: playerPmc.Customization.Head,
|
head: playerPmc.Customization.Head,
|
||||||
body: playerPmc.Customization.Body,
|
body: playerPmc.Customization.Body,
|
||||||
feet: playerPmc.Customization.Feet,
|
feet: playerPmc.Customization.Feet,
|
||||||
hands: playerPmc.Customization.Hands
|
hands: playerPmc.Customization.Hands,
|
||||||
},
|
},
|
||||||
skills: playerPmc.Skills,
|
skills: playerPmc.Skills,
|
||||||
equipment: {
|
equipment: {
|
||||||
// Default inventory tpl
|
// Default inventory tpl
|
||||||
Id: playerPmc.Inventory.items.find(x => x._tpl === "55d7217a4bdc2d86028b456d")._id,
|
Id: playerPmc.Inventory.items.find((x) => x._tpl === "55d7217a4bdc2d86028b456d")._id,
|
||||||
Items: playerPmc.Inventory.items
|
Items: playerPmc.Inventory.items,
|
||||||
},
|
},
|
||||||
achievements: playerPmc.Achievements,
|
achievements: playerPmc.Achievements,
|
||||||
favoriteItems: playerPmc.Inventory.favoriteItems ?? [],
|
favoriteItems: playerPmc.Inventory.favoriteItems ?? [],
|
||||||
pmcStats: {
|
pmcStats: {
|
||||||
eft: {
|
eft: {
|
||||||
totalInGameTime: playerPmc.Stats.Eft.TotalInGameTime,
|
totalInGameTime: playerPmc.Stats.Eft.TotalInGameTime,
|
||||||
overAllCounters: playerPmc.Stats.Eft.OverallCounters
|
overAllCounters: playerPmc.Stats.Eft.OverallCounters,
|
||||||
}
|
},
|
||||||
},
|
},
|
||||||
scavStats: {
|
scavStats: {
|
||||||
eft: {
|
eft: {
|
||||||
totalInGameTime: player.characters.scav.Stats.Eft.TotalInGameTime,
|
totalInGameTime: player.characters.scav.Stats.Eft.TotalInGameTime,
|
||||||
overAllCounters: player.characters.scav.Stats.Eft.OverallCounters
|
overAllCounters: player.characters.scav.Stats.Eft.OverallCounters,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,9 @@ export class QuestController
|
|||||||
const trader = profile.TradersInfo[quest.traderId];
|
const trader = profile.TradersInfo[quest.traderId];
|
||||||
if (!trader)
|
if (!trader)
|
||||||
{
|
{
|
||||||
this.logger.debug(`Unable to show quest: ${quest.QuestName} as its for a trader: ${quest.traderId} that no longer exists.`);
|
this.logger.debug(
|
||||||
|
`Unable to show quest: ${quest.QuestName} as its for a trader: ${quest.traderId} that no longer exists.`,
|
||||||
|
);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -135,7 +137,9 @@ export class QuestController
|
|||||||
for (const conditionToFulfil of questRequirements)
|
for (const conditionToFulfil of questRequirements)
|
||||||
{
|
{
|
||||||
// If the previous quest isn't in the user profile, it hasn't been completed or started
|
// If the previous quest isn't in the user profile, it hasn't been completed or started
|
||||||
const prerequisiteQuest = profile.Quests.find((profileQuest) => conditionToFulfil.target.includes(profileQuest.qid));
|
const prerequisiteQuest = profile.Quests.find((profileQuest) =>
|
||||||
|
conditionToFulfil.target.includes(profileQuest.qid)
|
||||||
|
);
|
||||||
if (!prerequisiteQuest)
|
if (!prerequisiteQuest)
|
||||||
{
|
{
|
||||||
haveCompletedPreviousQuest = false;
|
haveCompletedPreviousQuest = false;
|
||||||
@ -307,10 +311,10 @@ export class QuestController
|
|||||||
): IItemEventRouterResponse
|
): IItemEventRouterResponse
|
||||||
{
|
{
|
||||||
const acceptQuestResponse = this.eventOutputHolder.getOutput(sessionID);
|
const acceptQuestResponse = this.eventOutputHolder.getOutput(sessionID);
|
||||||
|
|
||||||
// Does quest exist in profile
|
// Does quest exist in profile
|
||||||
// Restarting a failed quest can mean quest exists in profile
|
// Restarting a failed quest can mean quest exists in profile
|
||||||
const existingQuestStatus = pmcData.Quests.find((x) => x.qid === acceptedQuest.qid)
|
const existingQuestStatus = pmcData.Quests.find((x) => x.qid === acceptedQuest.qid);
|
||||||
if (existingQuestStatus)
|
if (existingQuestStatus)
|
||||||
{
|
{
|
||||||
// Update existing
|
// Update existing
|
||||||
@ -356,9 +360,10 @@ export class QuestController
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Having accepted new quest, look for newly unlocked quests and inform client of them
|
// Having accepted new quest, look for newly unlocked quests and inform client of them
|
||||||
acceptQuestResponse.profileChanges[sessionID].quests.push(...this.questHelper
|
acceptQuestResponse.profileChanges[sessionID].quests.push(
|
||||||
.getNewlyAccessibleQuestsWhenStartingQuest(acceptedQuest.qid, sessionID));
|
...this.questHelper.getNewlyAccessibleQuestsWhenStartingQuest(acceptedQuest.qid, sessionID),
|
||||||
|
);
|
||||||
|
|
||||||
return acceptQuestResponse;
|
return acceptQuestResponse;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -380,7 +385,11 @@ export class QuestController
|
|||||||
const acceptQuestResponse = this.eventOutputHolder.getOutput(sessionID);
|
const acceptQuestResponse = this.eventOutputHolder.getOutput(sessionID);
|
||||||
|
|
||||||
// Create and store quest status object inside player profile
|
// Create and store quest status object inside player profile
|
||||||
const newRepeatableQuest = this.questHelper.getQuestReadyForProfile(pmcData, QuestStatus.Started, acceptedQuest);
|
const newRepeatableQuest = this.questHelper.getQuestReadyForProfile(
|
||||||
|
pmcData,
|
||||||
|
QuestStatus.Started,
|
||||||
|
acceptedQuest,
|
||||||
|
);
|
||||||
pmcData.Quests.push(newRepeatableQuest);
|
pmcData.Quests.push(newRepeatableQuest);
|
||||||
|
|
||||||
// Look for the generated quest cache in profile.RepeatableQuests
|
// Look for the generated quest cache in profile.RepeatableQuests
|
||||||
@ -431,7 +440,7 @@ export class QuestController
|
|||||||
|
|
||||||
if (!acceptQuestResponse.profileChanges[sessionID].repeatableQuests)
|
if (!acceptQuestResponse.profileChanges[sessionID].repeatableQuests)
|
||||||
{
|
{
|
||||||
acceptQuestResponse.profileChanges[sessionID].repeatableQuests = []
|
acceptQuestResponse.profileChanges[sessionID].repeatableQuests = [];
|
||||||
}
|
}
|
||||||
acceptQuestResponse.profileChanges[sessionID].repeatableQuests.push(responseData);
|
acceptQuestResponse.profileChanges[sessionID].repeatableQuests.push(responseData);
|
||||||
|
|
||||||
@ -510,7 +519,9 @@ export class QuestController
|
|||||||
// Check if it's a repeatable quest. If so, remove from Quests
|
// Check if it's a repeatable quest. If so, remove from Quests
|
||||||
for (const currentRepeatable of pmcData.RepeatableQuests)
|
for (const currentRepeatable of pmcData.RepeatableQuests)
|
||||||
{
|
{
|
||||||
const repeatableQuest = currentRepeatable.activeQuests.find((activeRepeatable) => activeRepeatable._id === completedQuestId);
|
const repeatableQuest = currentRepeatable.activeQuests.find((activeRepeatable) =>
|
||||||
|
activeRepeatable._id === completedQuestId
|
||||||
|
);
|
||||||
if (repeatableQuest)
|
if (repeatableQuest)
|
||||||
{
|
{
|
||||||
// Need to remove redundant scav quest object as its no longer necessary, is tracked in pmc profile
|
// Need to remove redundant scav quest object as its no longer necessary, is tracked in pmc profile
|
||||||
@ -633,8 +644,7 @@ export class QuestController
|
|||||||
if (nextQuestWaitCondition)
|
if (nextQuestWaitCondition)
|
||||||
{
|
{
|
||||||
// Now + wait time
|
// Now + wait time
|
||||||
const availableAfterTimestamp = this.timeUtil.getTimestamp()
|
const availableAfterTimestamp = this.timeUtil.getTimestamp() + nextQuestWaitCondition.availableAfter;
|
||||||
+ nextQuestWaitCondition.availableAfter;
|
|
||||||
|
|
||||||
// Update quest in profile with status of AvailableAfter
|
// Update quest in profile with status of AvailableAfter
|
||||||
const existingQuestInProfile = pmcData.Quests.find((x) => x.qid === quest._id);
|
const existingQuestInProfile = pmcData.Quests.find((x) => x.qid === quest._id);
|
||||||
@ -912,7 +922,8 @@ export class QuestController
|
|||||||
id: conditionId,
|
id: conditionId,
|
||||||
sourceId: questId,
|
sourceId: questId,
|
||||||
type: "HandoverItem",
|
type: "HandoverItem",
|
||||||
value: counterValue };
|
value: counterValue,
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -97,7 +97,7 @@ export class RagfairController
|
|||||||
const pmcProfile = this.profileHelper.getPmcProfile(sessionID);
|
const pmcProfile = this.profileHelper.getPmcProfile(sessionID);
|
||||||
|
|
||||||
result.offers = this.getOffersForSearchType(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
|
result.offers = this.getOffersForSearchType(searchRequest, itemsToAdd, traderAssorts, pmcProfile);
|
||||||
|
|
||||||
if (searchRequest.updateOfferCount)
|
if (searchRequest.updateOfferCount)
|
||||||
{
|
{
|
||||||
result.categories = this.getSpecificCategories(pmcProfile, searchRequest, result.offers);
|
result.categories = this.getSpecificCategories(pmcProfile, searchRequest, result.offers);
|
||||||
@ -158,7 +158,7 @@ export class RagfairController
|
|||||||
public getOfferById(sessionId: string, request: IGetRagfairOfferByIdRequest): IRagfairOffer
|
public getOfferById(sessionId: string, request: IGetRagfairOfferByIdRequest): IRagfairOffer
|
||||||
{
|
{
|
||||||
const offers = this.ragfairOfferService.getOffers();
|
const offers = this.ragfairOfferService.getOffers();
|
||||||
const offerToReturn = offers.find(x => x.intId === request.id);
|
const offerToReturn = offers.find((x) => x.intId === request.id);
|
||||||
|
|
||||||
return offerToReturn;
|
return offerToReturn;
|
||||||
}
|
}
|
||||||
@ -199,10 +199,15 @@ export class RagfairController
|
|||||||
* @param offers ragfair offers to get categories for
|
* @param offers ragfair offers to get categories for
|
||||||
* @returns record with templates + counts
|
* @returns record with templates + counts
|
||||||
*/
|
*/
|
||||||
protected getSpecificCategories(pmcProfile: IPmcData, searchRequest: ISearchRequestData, offers: IRagfairOffer[]): Record<string, number>
|
protected getSpecificCategories(
|
||||||
|
pmcProfile: IPmcData,
|
||||||
|
searchRequest: ISearchRequestData,
|
||||||
|
offers: IRagfairOffer[],
|
||||||
|
): Record<string, number>
|
||||||
{
|
{
|
||||||
// Linked/required search categories
|
// Linked/required search categories
|
||||||
const playerHasFleaUnlocked = pmcProfile.Info.Level >= this.databaseServer.getTables().globals.config.RagFair.minUserLevel;
|
const playerHasFleaUnlocked =
|
||||||
|
pmcProfile.Info.Level >= this.databaseServer.getTables().globals.config.RagFair.minUserLevel;
|
||||||
let offerPool = [];
|
let offerPool = [];
|
||||||
if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest))
|
if (this.isLinkedSearch(searchRequest) || this.isRequiredSearch(searchRequest))
|
||||||
{
|
{
|
||||||
@ -698,7 +703,9 @@ export class RagfairController
|
|||||||
if (playerOfferIndex === -1)
|
if (playerOfferIndex === -1)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
this.localisationService.getText("ragfair-offer_not_found_in_profile", { offerId: removeRequest.offerId }),
|
this.localisationService.getText("ragfair-offer_not_found_in_profile", {
|
||||||
|
offerId: removeRequest.offerId,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
return this.httpResponse.appendErrorToOutput(
|
return this.httpResponse.appendErrorToOutput(
|
||||||
output,
|
output,
|
||||||
@ -735,7 +742,9 @@ export class RagfairController
|
|||||||
if (playerOfferIndex === -1)
|
if (playerOfferIndex === -1)
|
||||||
{
|
{
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
this.localisationService.getText("ragfair-offer_not_found_in_profile", { offerId: extendRequest.offerId }),
|
this.localisationService.getText("ragfair-offer_not_found_in_profile", {
|
||||||
|
offerId: extendRequest.offerId,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
return this.httpResponse.appendErrorToOutput(
|
return this.httpResponse.appendErrorToOutput(
|
||||||
output,
|
output,
|
||||||
|
@ -83,7 +83,7 @@ export class RepeatableQuestController
|
|||||||
*
|
*
|
||||||
* @param {string} _info Request from client
|
* @param {string} _info Request from client
|
||||||
* @param {string} sessionID Player's session id
|
* @param {string} sessionID Player's session id
|
||||||
*
|
*
|
||||||
* @returns {array} Array of "repeatableQuestObjects" as descibed above
|
* @returns {array} Array of "repeatableQuestObjects" as descibed above
|
||||||
*/
|
*/
|
||||||
public getClientRepeatableQuests(_info: IEmptyRequestData, sessionID: string): IPmcDataRepeatableQuest[]
|
public getClientRepeatableQuests(_info: IEmptyRequestData, sessionID: string): IPmcDataRepeatableQuest[]
|
||||||
@ -120,7 +120,7 @@ export class RepeatableQuestController
|
|||||||
for (const activeQuest of currentRepeatableQuestType.activeQuests)
|
for (const activeQuest of currentRepeatableQuestType.activeQuests)
|
||||||
{
|
{
|
||||||
// Keep finished quests in list so player can hand in
|
// Keep finished quests in list so player can hand in
|
||||||
const quest = pmcData.Quests.find(quest => quest.qid === activeQuest._id);
|
const quest = pmcData.Quests.find((quest) => quest.qid === activeQuest._id);
|
||||||
if (quest)
|
if (quest)
|
||||||
{
|
{
|
||||||
if (quest.status === QuestStatus.AvailableForFinish)
|
if (quest.status === QuestStatus.AvailableForFinish)
|
||||||
@ -136,7 +136,7 @@ export class RepeatableQuestController
|
|||||||
this.profileFixerService.removeDanglingConditionCounters(pmcData);
|
this.profileFixerService.removeDanglingConditionCounters(pmcData);
|
||||||
|
|
||||||
// Remove expired quest from pmc.quest array
|
// Remove expired quest from pmc.quest array
|
||||||
pmcData.Quests = pmcData.Quests.filter(quest => quest.qid !== activeQuest._id);
|
pmcData.Quests = pmcData.Quests.filter((quest) => quest.qid !== activeQuest._id);
|
||||||
currentRepeatableQuestType.inactiveQuests.push(activeQuest);
|
currentRepeatableQuestType.inactiveQuests.push(activeQuest);
|
||||||
}
|
}
|
||||||
currentRepeatableQuestType.activeQuests = questsToKeep;
|
currentRepeatableQuestType.activeQuests = questsToKeep;
|
||||||
|
@ -11,7 +11,10 @@ import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEve
|
|||||||
import { IRagfairOffer } from "@spt-aki/models/eft/ragfair/IRagfairOffer";
|
import { IRagfairOffer } from "@spt-aki/models/eft/ragfair/IRagfairOffer";
|
||||||
import { IProcessBaseTradeRequestData } from "@spt-aki/models/eft/trade/IProcessBaseTradeRequestData";
|
import { IProcessBaseTradeRequestData } from "@spt-aki/models/eft/trade/IProcessBaseTradeRequestData";
|
||||||
import { IProcessBuyTradeRequestData } from "@spt-aki/models/eft/trade/IProcessBuyTradeRequestData";
|
import { IProcessBuyTradeRequestData } from "@spt-aki/models/eft/trade/IProcessBuyTradeRequestData";
|
||||||
import { IOfferRequest, IProcessRagfairTradeRequestData } from "@spt-aki/models/eft/trade/IProcessRagfairTradeRequestData";
|
import {
|
||||||
|
IOfferRequest,
|
||||||
|
IProcessRagfairTradeRequestData,
|
||||||
|
} from "@spt-aki/models/eft/trade/IProcessRagfairTradeRequestData";
|
||||||
import { IProcessSellTradeRequestData } from "@spt-aki/models/eft/trade/IProcessSellTradeRequestData";
|
import { IProcessSellTradeRequestData } from "@spt-aki/models/eft/trade/IProcessSellTradeRequestData";
|
||||||
import { ISellScavItemsToFenceRequestData } from "@spt-aki/models/eft/trade/ISellScavItemsToFenceRequestData";
|
import { ISellScavItemsToFenceRequestData } from "@spt-aki/models/eft/trade/ISellScavItemsToFenceRequestData";
|
||||||
import { BackendErrorCodes } from "@spt-aki/models/enums/BackendErrorCodes";
|
import { BackendErrorCodes } from "@spt-aki/models/enums/BackendErrorCodes";
|
||||||
@ -146,14 +149,20 @@ export class TradeController
|
|||||||
* @param requestOffer request data from client
|
* @param requestOffer request data from client
|
||||||
* @param output Output to send back to client
|
* @param output Output to send back to client
|
||||||
*/
|
*/
|
||||||
protected buyTraderItemFromRagfair(sessionId: string, pmcData: IPmcData, fleaOffer: IRagfairOffer, requestOffer: IOfferRequest, output: IItemEventRouterResponse): void
|
protected buyTraderItemFromRagfair(
|
||||||
|
sessionId: string,
|
||||||
|
pmcData: IPmcData,
|
||||||
|
fleaOffer: IRagfairOffer,
|
||||||
|
requestOffer: IOfferRequest,
|
||||||
|
output: IItemEventRouterResponse,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
// Skip buying items when player doesn't have needed loyalty
|
// Skip buying items when player doesn't have needed loyalty
|
||||||
if (this.playerLacksTraderLoyaltyLevelToBuyOffer(fleaOffer, pmcData))
|
if (this.playerLacksTraderLoyaltyLevelToBuyOffer(fleaOffer, pmcData))
|
||||||
{
|
{
|
||||||
const errorMessage = `Unable to buy item: ${
|
const errorMessage = `Unable to buy item: ${
|
||||||
fleaOffer.items[0]._tpl
|
fleaOffer.items[0]._tpl
|
||||||
} from trader: ${fleaOffer.user.id} as loyalty level too low, skipping`
|
} from trader: ${fleaOffer.user.id} as loyalty level too low, skipping`;
|
||||||
this.logger.debug(errorMessage);
|
this.logger.debug(errorMessage);
|
||||||
|
|
||||||
this.httpResponse.appendErrorToOutput(output, errorMessage, BackendErrorCodes.RAGFAIRUNAVAILABLE);
|
this.httpResponse.appendErrorToOutput(output, errorMessage, BackendErrorCodes.RAGFAIRUNAVAILABLE);
|
||||||
@ -182,7 +191,13 @@ export class TradeController
|
|||||||
* @param requestOffer Request data from client
|
* @param requestOffer Request data from client
|
||||||
* @param output Output to send back to client
|
* @param output Output to send back to client
|
||||||
*/
|
*/
|
||||||
protected buyPmcItemFromRagfair(sessionId: string, pmcData: IPmcData, fleaOffer: IRagfairOffer, requestOffer: IOfferRequest, output: IItemEventRouterResponse): void
|
protected buyPmcItemFromRagfair(
|
||||||
|
sessionId: string,
|
||||||
|
pmcData: IPmcData,
|
||||||
|
fleaOffer: IRagfairOffer,
|
||||||
|
requestOffer: IOfferRequest,
|
||||||
|
output: IItemEventRouterResponse,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
const buyData: IProcessBuyTradeRequestData = {
|
const buyData: IProcessBuyTradeRequestData = {
|
||||||
Action: "TradingConfirm",
|
Action: "TradingConfirm",
|
||||||
@ -198,7 +213,13 @@ export class TradeController
|
|||||||
};
|
};
|
||||||
|
|
||||||
// buyItem() must occur prior to removing the offer stack, otherwise item inside offer doesn't exist for confirmTrading() to use
|
// buyItem() must occur prior to removing the offer stack, otherwise item inside offer doesn't exist for confirmTrading() to use
|
||||||
this.tradeHelper.buyItem(pmcData, buyData, sessionId, this.ragfairConfig.dynamic.purchasesAreFoundInRaid, output);
|
this.tradeHelper.buyItem(
|
||||||
|
pmcData,
|
||||||
|
buyData,
|
||||||
|
sessionId,
|
||||||
|
this.ragfairConfig.dynamic.purchasesAreFoundInRaid,
|
||||||
|
output,
|
||||||
|
);
|
||||||
if (output.warnings.length > 0)
|
if (output.warnings.length > 0)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
@ -231,10 +252,7 @@ export class TradeController
|
|||||||
const scavProfile = this.profileHelper.getFullProfile(sessionId)?.characters?.scav;
|
const scavProfile = this.profileHelper.getFullProfile(sessionId)?.characters?.scav;
|
||||||
if (!scavProfile)
|
if (!scavProfile)
|
||||||
{
|
{
|
||||||
return this.httpResponse.appendErrorToOutput(
|
return this.httpResponse.appendErrorToOutput(output, `Profile ${request.fromOwner.id} has no scav account`);
|
||||||
output,
|
|
||||||
`Profile ${request.fromOwner.id} has no scav account`,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
this.sellInventoryToTrader(sessionId, scavProfile, pmcData, Traders.FENCE, output);
|
this.sellInventoryToTrader(sessionId, scavProfile, pmcData, Traders.FENCE, output);
|
||||||
@ -256,7 +274,7 @@ export class TradeController
|
|||||||
profileWithItemsToSell: IPmcData,
|
profileWithItemsToSell: IPmcData,
|
||||||
profileThatGetsMoney: IPmcData,
|
profileThatGetsMoney: IPmcData,
|
||||||
trader: Traders,
|
trader: Traders,
|
||||||
output: IItemEventRouterResponse
|
output: IItemEventRouterResponse,
|
||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
const handbookPrices = this.ragfairPriceService.getAllStaticPrices();
|
const handbookPrices = this.ragfairPriceService.getAllStaticPrices();
|
||||||
@ -335,4 +353,4 @@ export class TradeController
|
|||||||
|
|
||||||
return totalPrice;
|
return totalPrice;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,8 @@ export class WeatherController
|
|||||||
time: "",
|
time: "",
|
||||||
date: "",
|
date: "",
|
||||||
weather: null,
|
weather: null,
|
||||||
winterEventEnabled: this.weatherConfig.forceWinterEvent };
|
winterEventEnabled: this.weatherConfig.forceWinterEvent,
|
||||||
|
};
|
||||||
|
|
||||||
result = this.weatherGenerator.calculateGameTime(result);
|
result = this.weatherGenerator.calculateGameTime(result);
|
||||||
result.weather = this.weatherGenerator.generateWeather();
|
result.weather = this.weatherGenerator.generateWeather();
|
||||||
|
@ -485,7 +485,9 @@ export class Container
|
|||||||
depContainer.register<RagfairStaticRouter>("RagfairStaticRouter", { useClass: RagfairStaticRouter });
|
depContainer.register<RagfairStaticRouter>("RagfairStaticRouter", { useClass: RagfairStaticRouter });
|
||||||
depContainer.register<TraderStaticRouter>("TraderStaticRouter", { useClass: TraderStaticRouter });
|
depContainer.register<TraderStaticRouter>("TraderStaticRouter", { useClass: TraderStaticRouter });
|
||||||
depContainer.register<WeatherStaticRouter>("WeatherStaticRouter", { useClass: WeatherStaticRouter });
|
depContainer.register<WeatherStaticRouter>("WeatherStaticRouter", { useClass: WeatherStaticRouter });
|
||||||
depContainer.register<AchievementStaticRouter>("AchievementStaticRouter", { useClass: AchievementStaticRouter });
|
depContainer.register<AchievementStaticRouter>("AchievementStaticRouter", {
|
||||||
|
useClass: AchievementStaticRouter,
|
||||||
|
});
|
||||||
depContainer.register<BuildsStaticRouter>("BuildsStaticRouter", { useClass: BuildsStaticRouter });
|
depContainer.register<BuildsStaticRouter>("BuildsStaticRouter", { useClass: BuildsStaticRouter });
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -80,7 +80,9 @@ export class BotEquipmentModGenerator
|
|||||||
const compatibleModsPool = settings.modPool[parentTemplate._id];
|
const compatibleModsPool = settings.modPool[parentTemplate._id];
|
||||||
if (!compatibleModsPool)
|
if (!compatibleModsPool)
|
||||||
{
|
{
|
||||||
this.logger.warning(`bot: ${settings.botRole} lacks a mod slot pool for item: ${parentTemplate._id} ${parentTemplate._name}`);
|
this.logger.warning(
|
||||||
|
`bot: ${settings.botRole} lacks a mod slot pool for item: ${parentTemplate._id} ${parentTemplate._name}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over mod pool and choose mods to add to item
|
// Iterate over mod pool and choose mods to add to item
|
||||||
@ -94,12 +96,16 @@ export class BotEquipmentModGenerator
|
|||||||
modSlot: modSlotName,
|
modSlot: modSlotName,
|
||||||
parentId: parentTemplate._id,
|
parentId: parentTemplate._id,
|
||||||
parentName: parentTemplate._name,
|
parentName: parentTemplate._name,
|
||||||
botRole: settings.botRole
|
botRole: settings.botRole,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const modSpawnResult = this.shouldModBeSpawned(itemSlotTemplate, modSlotName.toLowerCase(), settings.spawnChances.equipmentMods);
|
const modSpawnResult = this.shouldModBeSpawned(
|
||||||
|
itemSlotTemplate,
|
||||||
|
modSlotName.toLowerCase(),
|
||||||
|
settings.spawnChances.equipmentMods,
|
||||||
|
);
|
||||||
if (modSpawnResult === ModSpawn.SKIP && !forceSpawn)
|
if (modSpawnResult === ModSpawn.SKIP && !forceSpawn)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
@ -112,37 +118,48 @@ export class BotEquipmentModGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
let modPoolToChooseFrom = compatibleModsPool[modSlotName];
|
let modPoolToChooseFrom = compatibleModsPool[modSlotName];
|
||||||
if (settings.botEquipmentConfig.filterPlatesByLevel && this.itemHelper.isRemovablePlateSlot(modSlotName.toLowerCase()))
|
if (
|
||||||
|
settings.botEquipmentConfig.filterPlatesByLevel
|
||||||
|
&& this.itemHelper.isRemovablePlateSlot(modSlotName.toLowerCase())
|
||||||
|
)
|
||||||
{
|
{
|
||||||
const outcome = this.filterPlateModsForSlotByLevel(settings, modSlotName.toLowerCase(), compatibleModsPool[modSlotName], parentTemplate);
|
const outcome = this.filterPlateModsForSlotByLevel(
|
||||||
|
settings,
|
||||||
|
modSlotName.toLowerCase(),
|
||||||
|
compatibleModsPool[modSlotName],
|
||||||
|
parentTemplate,
|
||||||
|
);
|
||||||
if ([Result.UNKNOWN_FAILURE, Result.NO_DEFAULT_FILTER].includes(outcome.result))
|
if ([Result.UNKNOWN_FAILURE, Result.NO_DEFAULT_FILTER].includes(outcome.result))
|
||||||
{
|
{
|
||||||
this.logger.debug(`Plate slot: ${modSlotName} selection for armor: ${parentTemplate._id} failed: ${Result[outcome.result]}, skipping`);
|
this.logger.debug(
|
||||||
|
`Plate slot: ${modSlotName} selection for armor: ${parentTemplate._id} failed: ${
|
||||||
|
Result[outcome.result]
|
||||||
|
}, skipping`,
|
||||||
|
);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if ([Result.LACKS_PLATE_WEIGHTS].includes(outcome.result))
|
if ([Result.LACKS_PLATE_WEIGHTS].includes(outcome.result))
|
||||||
{
|
{
|
||||||
this.logger.warning(`Plate slot: ${modSlotName} lacks weights for armor: ${parentTemplate._id}, unable to adjust plate choice, using existing data`);
|
this.logger.warning(
|
||||||
|
`Plate slot: ${modSlotName} lacks weights for armor: ${parentTemplate._id}, unable to adjust plate choice, using existing data`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
modPoolToChooseFrom = outcome.plateModTpls;
|
modPoolToChooseFrom = outcome.plateModTpls;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find random mod and check its compatible
|
// Find random mod and check its compatible
|
||||||
let modTpl: string;
|
let modTpl: string;
|
||||||
let found = false;
|
let found = false;
|
||||||
const exhaustableModPool = new ExhaustableArray(
|
const exhaustableModPool = new ExhaustableArray(modPoolToChooseFrom, this.randomUtil, this.jsonUtil);
|
||||||
modPoolToChooseFrom,
|
|
||||||
this.randomUtil,
|
|
||||||
this.jsonUtil,
|
|
||||||
);
|
|
||||||
while (exhaustableModPool.hasValues())
|
while (exhaustableModPool.hasValues())
|
||||||
{
|
{
|
||||||
modTpl = exhaustableModPool.getRandomValue();
|
modTpl = exhaustableModPool.getRandomValue();
|
||||||
if (
|
if (
|
||||||
!this.botGeneratorHelper.isItemIncompatibleWithCurrentItems(equipment, modTpl, modSlotName).incompatible
|
!this.botGeneratorHelper.isItemIncompatibleWithCurrentItems(equipment, modTpl, modSlotName)
|
||||||
|
.incompatible
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
found = true;
|
found = true;
|
||||||
@ -178,13 +195,7 @@ export class BotEquipmentModGenerator
|
|||||||
if (Object.keys(settings.modPool).includes(modTpl))
|
if (Object.keys(settings.modPool).includes(modTpl))
|
||||||
{
|
{
|
||||||
// Call self recursively with item being checkced item we just added to bot
|
// Call self recursively with item being checkced item we just added to bot
|
||||||
this.generateModsForEquipment(
|
this.generateModsForEquipment(equipment, modId, modTemplate[1], settings, forceSpawn);
|
||||||
equipment,
|
|
||||||
modId,
|
|
||||||
modTemplate[1],
|
|
||||||
settings,
|
|
||||||
forceSpawn,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -196,15 +207,17 @@ export class BotEquipmentModGenerator
|
|||||||
* @param settings Bot equipment generation settings
|
* @param settings Bot equipment generation settings
|
||||||
* @param modSlot Armor slot being filtered
|
* @param modSlot Armor slot being filtered
|
||||||
* @param existingPlateTplPool Plates tpls to choose from
|
* @param existingPlateTplPool Plates tpls to choose from
|
||||||
* @param armorItem
|
* @param armorItem
|
||||||
* @returns Array of plate tpls to choose from
|
* @returns Array of plate tpls to choose from
|
||||||
*/
|
*/
|
||||||
protected filterPlateModsForSlotByLevel(settings: IGenerateEquipmentProperties, modSlot: string, existingPlateTplPool: string[], armorItem: ITemplateItem): IFilterPlateModsForSlotByLevelResult
|
protected filterPlateModsForSlotByLevel(
|
||||||
|
settings: IGenerateEquipmentProperties,
|
||||||
|
modSlot: string,
|
||||||
|
existingPlateTplPool: string[],
|
||||||
|
armorItem: ITemplateItem,
|
||||||
|
): IFilterPlateModsForSlotByLevelResult
|
||||||
{
|
{
|
||||||
const result: IFilterPlateModsForSlotByLevelResult = {
|
const result: IFilterPlateModsForSlotByLevelResult = { result: Result.UNKNOWN_FAILURE, plateModTpls: null };
|
||||||
result: Result.UNKNOWN_FAILURE,
|
|
||||||
plateModTpls: null
|
|
||||||
};
|
|
||||||
|
|
||||||
// Not pmc or not a plate slot, return original mod pool array
|
// Not pmc or not a plate slot, return original mod pool array
|
||||||
if (!this.itemHelper.isRemovablePlateSlot(modSlot))
|
if (!this.itemHelper.isRemovablePlateSlot(modSlot))
|
||||||
@ -216,10 +229,9 @@ export class BotEquipmentModGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Get the front/back/side weights based on bots level
|
// Get the front/back/side weights based on bots level
|
||||||
const plateSlotWeights = settings
|
const plateSlotWeights = settings.botEquipmentConfig?.armorPlateWeighting?.find((x) =>
|
||||||
.botEquipmentConfig
|
settings.botLevel >= x.levelRange.min && settings.botLevel <= x.levelRange.max
|
||||||
?.armorPlateWeighting
|
);
|
||||||
?.find(x => settings.botLevel >= x.levelRange.min && settings.botLevel <= x.levelRange.max);
|
|
||||||
if (!plateSlotWeights)
|
if (!plateSlotWeights)
|
||||||
{
|
{
|
||||||
// No weights, return original array of plate tpls
|
// No weights, return original array of plate tpls
|
||||||
@ -242,18 +254,20 @@ export class BotEquipmentModGenerator
|
|||||||
|
|
||||||
// Choose a plate level based on weighting
|
// Choose a plate level based on weighting
|
||||||
const chosenArmorPlateLevel = this.weightedRandomHelper.getWeightedValue<string>(plateWeights);
|
const chosenArmorPlateLevel = this.weightedRandomHelper.getWeightedValue<string>(plateWeights);
|
||||||
|
|
||||||
// Convert the array of ids into database items
|
// Convert the array of ids into database items
|
||||||
const platesFromDb = existingPlateTplPool.map(x => this.itemHelper.getItem(x)[1]);
|
const platesFromDb = existingPlateTplPool.map((x) => this.itemHelper.getItem(x)[1]);
|
||||||
|
|
||||||
// Filter plates to the chosen level based on its armorClass property
|
// Filter plates to the chosen level based on its armorClass property
|
||||||
const filteredPlates = platesFromDb.filter(x => x._props.armorClass === chosenArmorPlateLevel);
|
const filteredPlates = platesFromDb.filter((x) => x._props.armorClass === chosenArmorPlateLevel);
|
||||||
if (filteredPlates.length === 0)
|
if (filteredPlates.length === 0)
|
||||||
{
|
{
|
||||||
this.logger.debug(`Plate filter was too restrictive for armor: ${armorItem._id}, unable to find plates of level: ${chosenArmorPlateLevel}. Using mod items default plate`);
|
this.logger.debug(
|
||||||
|
`Plate filter was too restrictive for armor: ${armorItem._id}, unable to find plates of level: ${chosenArmorPlateLevel}. Using mod items default plate`,
|
||||||
|
);
|
||||||
|
|
||||||
const relatedItemDbModSlot = armorItem._props.Slots.find(slot => slot._name.toLowerCase() === modSlot);
|
const relatedItemDbModSlot = armorItem._props.Slots.find((slot) => slot._name.toLowerCase() === modSlot);
|
||||||
const defaultPlate = relatedItemDbModSlot._props.filters[0].Plate
|
const defaultPlate = relatedItemDbModSlot._props.filters[0].Plate;
|
||||||
if (!defaultPlate)
|
if (!defaultPlate)
|
||||||
{
|
{
|
||||||
// No relevant plate found after filtering AND no default plate
|
// No relevant plate found after filtering AND no default plate
|
||||||
@ -262,7 +276,9 @@ export class BotEquipmentModGenerator
|
|||||||
const defaultPreset = this.presetHelper.getDefaultPreset(armorItem._id);
|
const defaultPreset = this.presetHelper.getDefaultPreset(armorItem._id);
|
||||||
if (defaultPreset)
|
if (defaultPreset)
|
||||||
{
|
{
|
||||||
const relatedPresetSlot = defaultPreset._items.find(item => item.slotId?.toLowerCase() === modSlot);
|
const relatedPresetSlot = defaultPreset._items.find((item) =>
|
||||||
|
item.slotId?.toLowerCase() === modSlot
|
||||||
|
);
|
||||||
if (relatedPresetSlot)
|
if (relatedPresetSlot)
|
||||||
{
|
{
|
||||||
result.result = Result.SUCCESS;
|
result.result = Result.SUCCESS;
|
||||||
@ -285,7 +301,7 @@ export class BotEquipmentModGenerator
|
|||||||
|
|
||||||
// Only return the items ids
|
// Only return the items ids
|
||||||
result.result = Result.SUCCESS;
|
result.result = Result.SUCCESS;
|
||||||
result.plateModTpls = filteredPlates.map(x => x._id);
|
result.plateModTpls = filteredPlates.map((x) => x._id);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -333,7 +349,7 @@ export class BotEquipmentModGenerator
|
|||||||
this.localisationService.getText("bot-unable_to_add_mods_to_weapon_missing_ammo_slot", {
|
this.localisationService.getText("bot-unable_to_add_mods_to_weapon_missing_ammo_slot", {
|
||||||
weaponName: parentTemplate._name,
|
weaponName: parentTemplate._name,
|
||||||
weaponId: parentTemplate._id,
|
weaponId: parentTemplate._id,
|
||||||
botRole: botRole
|
botRole: botRole,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
@ -385,7 +401,7 @@ export class BotEquipmentModGenerator
|
|||||||
weapon,
|
weapon,
|
||||||
ammoTpl,
|
ammoTpl,
|
||||||
parentTemplate,
|
parentTemplate,
|
||||||
modSpawnResult
|
modSpawnResult,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Compatible mod not found
|
// Compatible mod not found
|
||||||
@ -469,9 +485,7 @@ export class BotEquipmentModGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
const modId = this.hashUtil.generate();
|
const modId = this.hashUtil.generate();
|
||||||
weapon.push(
|
weapon.push(this.createModItem(modId, modToAddTemplate._id, weaponId, modSlot, modToAddTemplate, botRole));
|
||||||
this.createModItem(modId, modToAddTemplate._id, weaponId, modSlot, modToAddTemplate, botRole),
|
|
||||||
);
|
|
||||||
|
|
||||||
// I first thought we could use the recursive generateModsForItems as previously for cylinder magazines.
|
// I first thought we could use the recursive generateModsForItems as previously for cylinder magazines.
|
||||||
// However, the recursion doesn't go over the slots of the parent mod but over the modPool which is given by the bot config
|
// However, the recursion doesn't go over the slots of the parent mod but over the modPool which is given by the bot config
|
||||||
@ -699,7 +713,7 @@ export class BotEquipmentModGenerator
|
|||||||
const slotRequired = itemSlot._required;
|
const slotRequired = itemSlot._required;
|
||||||
if (this.getAmmoContainers().includes(modSlot))
|
if (this.getAmmoContainers().includes(modSlot))
|
||||||
{
|
{
|
||||||
return ModSpawn.SPAWN
|
return ModSpawn.SPAWN;
|
||||||
}
|
}
|
||||||
const spawnMod = this.probabilityHelper.rollChance(modSpawnChances[modSlot]);
|
const spawnMod = this.probabilityHelper.rollChance(modSpawnChances[modSlot]);
|
||||||
if (!spawnMod && slotRequired)
|
if (!spawnMod && slotRequired)
|
||||||
@ -708,9 +722,7 @@ export class BotEquipmentModGenerator
|
|||||||
return ModSpawn.DEFAULT_MOD;
|
return ModSpawn.DEFAULT_MOD;
|
||||||
}
|
}
|
||||||
|
|
||||||
return spawnMod
|
return spawnMod ? ModSpawn.SPAWN : ModSpawn.SKIP;
|
||||||
? ModSpawn.SPAWN
|
|
||||||
: ModSpawn.SKIP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -733,7 +745,7 @@ export class BotEquipmentModGenerator
|
|||||||
weapon: Item[],
|
weapon: Item[],
|
||||||
ammoTpl: string,
|
ammoTpl: string,
|
||||||
parentTemplate: ITemplateItem,
|
parentTemplate: ITemplateItem,
|
||||||
modSpawnResult: ModSpawn
|
modSpawnResult: ModSpawn,
|
||||||
): [boolean, ITemplateItem]
|
): [boolean, ITemplateItem]
|
||||||
{
|
{
|
||||||
/** Slot mod will fill */
|
/** Slot mod will fill */
|
||||||
@ -743,17 +755,23 @@ export class BotEquipmentModGenerator
|
|||||||
// It's ammo, use predefined ammo parameter
|
// It's ammo, use predefined ammo parameter
|
||||||
if (this.getAmmoContainers().includes(modSlot) && modSlot !== "mod_magazine")
|
if (this.getAmmoContainers().includes(modSlot) && modSlot !== "mod_magazine")
|
||||||
{
|
{
|
||||||
return this.itemHelper.getItem(ammoTpl)
|
return this.itemHelper.getItem(ammoTpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure there's a pool of mods to pick from
|
// Ensure there's a pool of mods to pick from
|
||||||
let modPool = this.getModPoolForSlot(itemModPool, modSpawnResult, parentTemplate, weaponTemplate, modSlot, botEquipBlacklist, isRandomisableSlot);
|
let modPool = this.getModPoolForSlot(
|
||||||
|
itemModPool,
|
||||||
|
modSpawnResult,
|
||||||
|
parentTemplate,
|
||||||
|
weaponTemplate,
|
||||||
|
modSlot,
|
||||||
|
botEquipBlacklist,
|
||||||
|
isRandomisableSlot,
|
||||||
|
);
|
||||||
if (!(modPool || parentSlot._required))
|
if (!(modPool || parentSlot._required))
|
||||||
{
|
{
|
||||||
// Nothing in mod pool + item not required
|
// Nothing in mod pool + item not required
|
||||||
this.logger.debug(
|
this.logger.debug(`Mod pool for slot: ${modSlot} on item: ${parentTemplate._name} was empty, skipping mod`);
|
||||||
`Mod pool for slot: ${modSlot} on item: ${parentTemplate._name} was empty, skipping mod`,
|
|
||||||
);
|
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -763,16 +781,18 @@ export class BotEquipmentModGenerator
|
|||||||
// scope pool has more than one scope
|
// scope pool has more than one scope
|
||||||
if (modPool.length > 1)
|
if (modPool.length > 1)
|
||||||
{
|
{
|
||||||
modPool = this.filterSightsByWeaponType(
|
modPool = this.filterSightsByWeaponType(weapon[0], modPool, botWeaponSightWhitelist);
|
||||||
weapon[0],
|
|
||||||
modPool,
|
|
||||||
botWeaponSightWhitelist,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick random mod that's compatible
|
// Pick random mod that's compatible
|
||||||
const chosenModResult = this.pickWeaponModTplForSlotFromPool(modPool, parentSlot, modSpawnResult, weapon, modSlot);
|
const chosenModResult = this.pickWeaponModTplForSlotFromPool(
|
||||||
|
modPool,
|
||||||
|
parentSlot,
|
||||||
|
modSpawnResult,
|
||||||
|
weapon,
|
||||||
|
modSlot,
|
||||||
|
);
|
||||||
if (chosenModResult.slotBlocked && !parentSlot._required)
|
if (chosenModResult.slotBlocked && !parentSlot._required)
|
||||||
{
|
{
|
||||||
// Don't bother trying to fit mod, slot is completely blocked
|
// Don't bother trying to fit mod, slot is completely blocked
|
||||||
@ -783,7 +803,7 @@ export class BotEquipmentModGenerator
|
|||||||
if (chosenModResult.incompatible && parentSlot._required)
|
if (chosenModResult.incompatible && parentSlot._required)
|
||||||
{
|
{
|
||||||
this.logger.debug(chosenModResult.reason);
|
this.logger.debug(chosenModResult.reason);
|
||||||
//this.logger.debug(`Weapon: ${weapon.map(x => `${x._tpl} ${x.slotId ?? ""}`).join(",")}`)
|
// this.logger.debug(`Weapon: ${weapon.map(x => `${x._tpl} ${x.slotId ?? ""}`).join(",")}`)
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get random mod to attach from items db for required slots if none found above
|
// Get random mod to attach from items db for required slots if none found above
|
||||||
@ -821,15 +841,12 @@ export class BotEquipmentModGenerator
|
|||||||
parentSlot: Slot,
|
parentSlot: Slot,
|
||||||
modSpawnResult: ModSpawn,
|
modSpawnResult: ModSpawn,
|
||||||
weapon: Item[],
|
weapon: Item[],
|
||||||
modSlotname: string): IChooseRandomCompatibleModResult
|
modSlotname: string,
|
||||||
|
): IChooseRandomCompatibleModResult
|
||||||
{
|
{
|
||||||
let chosenTpl: string;
|
let chosenTpl: string;
|
||||||
const exhaustableModPool = new ExhaustableArray(modPool, this.randomUtil, this.jsonUtil);
|
const exhaustableModPool = new ExhaustableArray(modPool, this.randomUtil, this.jsonUtil);
|
||||||
let chosenModResult: IChooseRandomCompatibleModResult = {
|
let chosenModResult: IChooseRandomCompatibleModResult = { incompatible: true, found: false, reason: "unknown" };
|
||||||
incompatible: true,
|
|
||||||
found: false,
|
|
||||||
reason: "unknown",
|
|
||||||
};
|
|
||||||
const modParentFilterList = parentSlot._props.filters[0].Filter;
|
const modParentFilterList = parentSlot._props.filters[0].Filter;
|
||||||
|
|
||||||
// How many times can a mod for the slot be blocked before we stop trying
|
// How many times can a mod for the slot be blocked before we stop trying
|
||||||
@ -876,7 +893,7 @@ export class BotEquipmentModGenerator
|
|||||||
// Try again
|
// Try again
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Some mod combos will never work, make sure this isnt the case
|
// Some mod combos will never work, make sure this isnt the case
|
||||||
if (!chosenModResult.incompatible && !this.weaponModComboIsIncompatible(weapon, chosenTpl))
|
if (!chosenModResult.incompatible && !this.weaponModComboIsIncompatible(weapon, chosenTpl))
|
||||||
{
|
{
|
||||||
@ -902,9 +919,9 @@ export class BotEquipmentModGenerator
|
|||||||
* @param parentTemplate Mods parent
|
* @param parentTemplate Mods parent
|
||||||
* @param weaponTemplate Mods root parent (weapon/equipment)
|
* @param weaponTemplate Mods root parent (weapon/equipment)
|
||||||
* @param modSlot name of mod slot to choose for
|
* @param modSlot name of mod slot to choose for
|
||||||
* @param botEquipBlacklist
|
* @param botEquipBlacklist
|
||||||
* @param isRandomisableSlot is flagged as a randomisable slot
|
* @param isRandomisableSlot is flagged as a randomisable slot
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
protected getModPoolForSlot(
|
protected getModPoolForSlot(
|
||||||
itemModPool: Record<string, string[]>,
|
itemModPool: Record<string, string[]>,
|
||||||
@ -913,13 +930,16 @@ export class BotEquipmentModGenerator
|
|||||||
weaponTemplate: ITemplateItem,
|
weaponTemplate: ITemplateItem,
|
||||||
modSlot: string,
|
modSlot: string,
|
||||||
botEquipBlacklist: EquipmentFilterDetails,
|
botEquipBlacklist: EquipmentFilterDetails,
|
||||||
isRandomisableSlot: boolean): string[]
|
isRandomisableSlot: boolean,
|
||||||
|
): string[]
|
||||||
{
|
{
|
||||||
// Mod is flagged as being default only, try and find it in globals
|
// Mod is flagged as being default only, try and find it in globals
|
||||||
if (modSpawnResult === ModSpawn.DEFAULT_MOD)
|
if (modSpawnResult === ModSpawn.DEFAULT_MOD)
|
||||||
{
|
{
|
||||||
const defaultWeaponPreset = this.presetHelper.getDefaultPreset(weaponTemplate._id)
|
const defaultWeaponPreset = this.presetHelper.getDefaultPreset(weaponTemplate._id);
|
||||||
const matchingMod = defaultWeaponPreset._items.find(item => item?.slotId?.toLowerCase() === modSlot.toLowerCase());
|
const matchingMod = defaultWeaponPreset._items.find((item) =>
|
||||||
|
item?.slotId?.toLowerCase() === modSlot.toLowerCase()
|
||||||
|
);
|
||||||
|
|
||||||
// Only filter mods down to single default item if it already exists in existing itemModPool, OR the default item has no children
|
// Only filter mods down to single default item if it already exists in existing itemModPool, OR the default item has no children
|
||||||
// Filtering mod pool to item that wasnt already there can have problems;
|
// Filtering mod pool to item that wasnt already there can have problems;
|
||||||
@ -1053,7 +1073,7 @@ export class BotEquipmentModGenerator
|
|||||||
slotAddedToTemplate: Slot,
|
slotAddedToTemplate: Slot,
|
||||||
modSlot: string,
|
modSlot: string,
|
||||||
parentTemplate: ITemplateItem,
|
parentTemplate: ITemplateItem,
|
||||||
botRole: string
|
botRole: string,
|
||||||
): boolean
|
): boolean
|
||||||
{
|
{
|
||||||
const modBeingAddedTemplate = modToAdd[1];
|
const modBeingAddedTemplate = modToAdd[1];
|
||||||
@ -1083,7 +1103,7 @@ export class BotEquipmentModGenerator
|
|||||||
itemName: modBeingAddedTemplate._name,
|
itemName: modBeingAddedTemplate._name,
|
||||||
modSlot: modSlot,
|
modSlot: modSlot,
|
||||||
parentItemName: parentTemplate._name,
|
parentItemName: parentTemplate._name,
|
||||||
botRole: botRole
|
botRole: botRole,
|
||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
@ -110,9 +110,7 @@ export class BotGenerator
|
|||||||
|
|
||||||
// Get raw json data for bot (Cloned)
|
// Get raw json data for bot (Cloned)
|
||||||
const botJsonTemplate = this.jsonUtil.clone(
|
const botJsonTemplate = this.jsonUtil.clone(
|
||||||
this.botHelper.getBotTemplate((botGenerationDetails.isPmc)
|
this.botHelper.getBotTemplate((botGenerationDetails.isPmc) ? bot.Info.Side : botGenerationDetails.role),
|
||||||
? bot.Info.Side
|
|
||||||
: botGenerationDetails.role),
|
|
||||||
);
|
);
|
||||||
|
|
||||||
bot = this.generateBot(sessionId, bot, botJsonTemplate, botGenerationDetails);
|
bot = this.generateBot(sessionId, bot, botJsonTemplate, botGenerationDetails);
|
||||||
@ -161,12 +159,7 @@ export class BotGenerator
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
bot.Info.Nickname = this.generateBotNickname(
|
bot.Info.Nickname = this.generateBotNickname(botJsonTemplate, botGenerationDetails, botRole, sessionId);
|
||||||
botJsonTemplate,
|
|
||||||
botGenerationDetails,
|
|
||||||
botRole,
|
|
||||||
sessionId,
|
|
||||||
);
|
|
||||||
|
|
||||||
if (!this.seasonalEventService.christmasEventEnabled())
|
if (!this.seasonalEventService.christmasEventEnabled())
|
||||||
{
|
{
|
||||||
|
@ -12,7 +12,12 @@ import { Chances, Generation, IBotType, Inventory, Mods } from "@spt-aki/models/
|
|||||||
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
import { EquipmentSlots } from "@spt-aki/models/enums/EquipmentSlots";
|
import { EquipmentSlots } from "@spt-aki/models/enums/EquipmentSlots";
|
||||||
import { EquipmentFilterDetails, EquipmentFilters, IBotConfig, RandomisationDetails } from "@spt-aki/models/spt/config/IBotConfig";
|
import {
|
||||||
|
EquipmentFilterDetails,
|
||||||
|
EquipmentFilters,
|
||||||
|
IBotConfig,
|
||||||
|
RandomisationDetails,
|
||||||
|
} from "@spt-aki/models/spt/config/IBotConfig";
|
||||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||||
@ -70,13 +75,7 @@ export class BotInventoryGenerator
|
|||||||
// Generate base inventory with no items
|
// Generate base inventory with no items
|
||||||
const botInventory = this.generateInventoryBase();
|
const botInventory = this.generateInventoryBase();
|
||||||
|
|
||||||
this.generateAndAddEquipmentToBot(
|
this.generateAndAddEquipmentToBot(templateInventory, wornItemChances, botRole, botInventory, botLevel);
|
||||||
templateInventory,
|
|
||||||
wornItemChances,
|
|
||||||
botRole,
|
|
||||||
botInventory,
|
|
||||||
botLevel,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Roll weapon spawns (primary/secondary/holster) and generate a weapon for each roll that passed
|
// Roll weapon spawns (primary/secondary/holster) and generate a weapon for each roll that passed
|
||||||
this.generateAndAddWeaponsToBot(
|
this.generateAndAddWeaponsToBot(
|
||||||
@ -91,13 +90,7 @@ export class BotInventoryGenerator
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Pick loot and add to bots containers (rig/backpack/pockets/secure)
|
// Pick loot and add to bots containers (rig/backpack/pockets/secure)
|
||||||
this.botLootGenerator.generateLoot(
|
this.botLootGenerator.generateLoot(sessionId, botJsonTemplate, isPmc, botRole, botInventory, botLevel);
|
||||||
sessionId,
|
|
||||||
botJsonTemplate,
|
|
||||||
isPmc,
|
|
||||||
botRole,
|
|
||||||
botInventory,
|
|
||||||
botLevel);
|
|
||||||
|
|
||||||
return botInventory;
|
return botInventory;
|
||||||
}
|
}
|
||||||
@ -138,7 +131,7 @@ export class BotInventoryGenerator
|
|||||||
sortingTable: sortingTableId,
|
sortingTable: sortingTableId,
|
||||||
hideoutAreaStashes: {},
|
hideoutAreaStashes: {},
|
||||||
fastPanel: {},
|
fastPanel: {},
|
||||||
favoriteItems: []
|
favoriteItems: [],
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -189,7 +182,7 @@ export class BotInventoryGenerator
|
|||||||
botLevel: botLevel,
|
botLevel: botLevel,
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails
|
randomisationDetails: randomistionDetails,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -203,7 +196,7 @@ export class BotInventoryGenerator
|
|||||||
botLevel: botLevel,
|
botLevel: botLevel,
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails
|
randomisationDetails: randomistionDetails,
|
||||||
});
|
});
|
||||||
this.generateEquipment({
|
this.generateEquipment({
|
||||||
rootEquipmentSlot: EquipmentSlots.HEADWEAR,
|
rootEquipmentSlot: EquipmentSlots.HEADWEAR,
|
||||||
@ -214,7 +207,7 @@ export class BotInventoryGenerator
|
|||||||
botLevel: botLevel,
|
botLevel: botLevel,
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails
|
randomisationDetails: randomistionDetails,
|
||||||
});
|
});
|
||||||
this.generateEquipment({
|
this.generateEquipment({
|
||||||
rootEquipmentSlot: EquipmentSlots.EARPIECE,
|
rootEquipmentSlot: EquipmentSlots.EARPIECE,
|
||||||
@ -225,7 +218,7 @@ export class BotInventoryGenerator
|
|||||||
botLevel: botLevel,
|
botLevel: botLevel,
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails
|
randomisationDetails: randomistionDetails,
|
||||||
});
|
});
|
||||||
this.generateEquipment({
|
this.generateEquipment({
|
||||||
rootEquipmentSlot: EquipmentSlots.ARMOR_VEST,
|
rootEquipmentSlot: EquipmentSlots.ARMOR_VEST,
|
||||||
@ -236,11 +229,11 @@ export class BotInventoryGenerator
|
|||||||
botLevel: botLevel,
|
botLevel: botLevel,
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails
|
randomisationDetails: randomistionDetails,
|
||||||
});
|
});
|
||||||
|
|
||||||
// Bot has no armor vest and flagged to be foreced to wear armored rig in this event
|
// Bot has no armor vest and flagged to be foreced to wear armored rig in this event
|
||||||
const hasArmorVest = botInventory.items.some(item => item.slotId === "ArmorVest")
|
const hasArmorVest = botInventory.items.some((item) => item.slotId === "ArmorVest");
|
||||||
if (botEquipConfig.forceOnlyArmoredRigWhenNoArmor && !hasArmorVest)
|
if (botEquipConfig.forceOnlyArmoredRigWhenNoArmor && !hasArmorVest)
|
||||||
{
|
{
|
||||||
// Filter rigs down to only those with armor
|
// Filter rigs down to only those with armor
|
||||||
@ -263,44 +256,48 @@ export class BotInventoryGenerator
|
|||||||
botLevel: botLevel,
|
botLevel: botLevel,
|
||||||
inventory: botInventory,
|
inventory: botInventory,
|
||||||
botEquipmentConfig: botEquipConfig,
|
botEquipmentConfig: botEquipConfig,
|
||||||
randomisationDetails: randomistionDetails
|
randomisationDetails: randomistionDetails,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove non-armored rigs from parameter data
|
* Remove non-armored rigs from parameter data
|
||||||
* @param templateInventory
|
* @param templateInventory
|
||||||
*/
|
*/
|
||||||
protected filterRigsToThoseWithProtection(templateInventory: Inventory): void
|
protected filterRigsToThoseWithProtection(templateInventory: Inventory): void
|
||||||
{
|
{
|
||||||
const tacVestsWithArmor = Object.entries(templateInventory.equipment.TacticalVest)
|
const tacVestsWithArmor = Object.entries(templateInventory.equipment.TacticalVest).reduce(
|
||||||
.reduce((newVestDictionary, [tplKey]) =>
|
(newVestDictionary, [tplKey]) =>
|
||||||
{
|
{
|
||||||
if (this.itemHelper.getItem(tplKey)[1]._props.Slots?.length > 0)
|
if (this.itemHelper.getItem(tplKey)[1]._props.Slots?.length > 0)
|
||||||
{
|
{
|
||||||
newVestDictionary[tplKey] = templateInventory.equipment.TacticalVest[tplKey];
|
newVestDictionary[tplKey] = templateInventory.equipment.TacticalVest[tplKey];
|
||||||
}
|
}
|
||||||
return newVestDictionary;
|
return newVestDictionary;
|
||||||
}, {});
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
templateInventory.equipment.TacticalVest = tacVestsWithArmor;
|
templateInventory.equipment.TacticalVest = tacVestsWithArmor;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove armored rigs from parameter data
|
* Remove armored rigs from parameter data
|
||||||
* @param templateInventory
|
* @param templateInventory
|
||||||
*/
|
*/
|
||||||
protected filterRigsToThoseWithoutProtection(templateInventory: Inventory): void
|
protected filterRigsToThoseWithoutProtection(templateInventory: Inventory): void
|
||||||
{
|
{
|
||||||
const tacVestsWithoutArmor = Object.entries(templateInventory.equipment.TacticalVest)
|
const tacVestsWithoutArmor = Object.entries(templateInventory.equipment.TacticalVest).reduce(
|
||||||
.reduce((newVestDictionary, [tplKey]) =>
|
(newVestDictionary, [tplKey]) =>
|
||||||
{
|
{
|
||||||
if (this.itemHelper.getItem(tplKey)[1]._props.Slots?.length === 0)
|
if (this.itemHelper.getItem(tplKey)[1]._props.Slots?.length === 0)
|
||||||
{
|
{
|
||||||
newVestDictionary[tplKey] = templateInventory.equipment.TacticalVest[tplKey];
|
newVestDictionary[tplKey] = templateInventory.equipment.TacticalVest[tplKey];
|
||||||
}
|
}
|
||||||
return newVestDictionary;
|
return newVestDictionary;
|
||||||
}, {});
|
},
|
||||||
|
{},
|
||||||
|
);
|
||||||
|
|
||||||
templateInventory.equipment.TacticalVest = tacVestsWithoutArmor;
|
templateInventory.equipment.TacticalVest = tacVestsWithoutArmor;
|
||||||
}
|
}
|
||||||
@ -312,13 +309,18 @@ export class BotInventoryGenerator
|
|||||||
protected generateEquipment(settings: IGenerateEquipmentProperties): void
|
protected generateEquipment(settings: IGenerateEquipmentProperties): void
|
||||||
{
|
{
|
||||||
const spawnChance =
|
const spawnChance =
|
||||||
([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[]).includes(settings.rootEquipmentSlot)
|
([EquipmentSlots.POCKETS, EquipmentSlots.SECURED_CONTAINER] as string[]).includes(
|
||||||
|
settings.rootEquipmentSlot,
|
||||||
|
)
|
||||||
? 100
|
? 100
|
||||||
: settings.spawnChances.equipment[settings.rootEquipmentSlot];
|
: settings.spawnChances.equipment[settings.rootEquipmentSlot];
|
||||||
if (typeof spawnChance === "undefined")
|
if (typeof spawnChance === "undefined")
|
||||||
{
|
{
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
this.localisationService.getText("bot-no_spawn_chance_defined_for_equipment_slot", settings.rootEquipmentSlot),
|
this.localisationService.getText(
|
||||||
|
"bot-no_spawn_chance_defined_for_equipment_slot",
|
||||||
|
settings.rootEquipmentSlot,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -358,7 +360,8 @@ export class BotInventoryGenerator
|
|||||||
const compatabilityResult = this.botGeneratorHelper.isItemIncompatibleWithCurrentItems(
|
const compatabilityResult = this.botGeneratorHelper.isItemIncompatibleWithCurrentItems(
|
||||||
settings.inventory.items,
|
settings.inventory.items,
|
||||||
chosenItemTpl,
|
chosenItemTpl,
|
||||||
settings.rootEquipmentSlot);
|
settings.rootEquipmentSlot,
|
||||||
|
);
|
||||||
if (compatabilityResult.incompatible)
|
if (compatabilityResult.incompatible)
|
||||||
{
|
{
|
||||||
// Tried x different items that failed, stop
|
// Tried x different items that failed, stop
|
||||||
@ -404,13 +407,13 @@ export class BotInventoryGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Item has slots, fill them
|
// Item has slots, fill them
|
||||||
if ( pickedItemDb._props.Slots?.length > 0 )
|
if (pickedItemDb._props.Slots?.length > 0)
|
||||||
{
|
{
|
||||||
const items = this.botEquipmentModGenerator.generateModsForEquipment(
|
const items = this.botEquipmentModGenerator.generateModsForEquipment(
|
||||||
[item],
|
[item],
|
||||||
id,
|
id,
|
||||||
pickedItemDb,
|
pickedItemDb,
|
||||||
settings
|
settings,
|
||||||
);
|
);
|
||||||
settings.inventory.items.push(...items);
|
settings.inventory.items.push(...items);
|
||||||
}
|
}
|
||||||
@ -558,20 +561,20 @@ export class BotInventoryGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface IGenerateEquipmentProperties
|
export interface IGenerateEquipmentProperties
|
||||||
{
|
{
|
||||||
/** Root Slot being generated */
|
/** Root Slot being generated */
|
||||||
rootEquipmentSlot: string,
|
rootEquipmentSlot: string;
|
||||||
/** Equipment pool for root slot being generated */
|
/** Equipment pool for root slot being generated */
|
||||||
rootEquipmentPool: Record<string, number>,
|
rootEquipmentPool: Record<string, number>;
|
||||||
modPool: Mods,
|
modPool: Mods;
|
||||||
/** Dictionary of mod items and their chance to spawn for this bot type */
|
/** Dictionary of mod items and their chance to spawn for this bot type */
|
||||||
spawnChances: Chances,
|
spawnChances: Chances;
|
||||||
/** Role being generated for */
|
/** Role being generated for */
|
||||||
botRole: string,
|
botRole: string;
|
||||||
/** Level of bot being generated */
|
/** Level of bot being generated */
|
||||||
botLevel: number,
|
botLevel: number;
|
||||||
inventory: PmcInventory,
|
inventory: PmcInventory;
|
||||||
botEquipmentConfig: EquipmentFilters,
|
botEquipmentConfig: EquipmentFilters;
|
||||||
/** Settings from bot.json to adjust how item is generated */
|
/** Settings from bot.json to adjust how item is generated */
|
||||||
randomisationDetails: RandomisationDetails
|
randomisationDetails: RandomisationDetails;
|
||||||
}
|
}
|
||||||
|
@ -43,7 +43,8 @@ export class BotLevelGenerator
|
|||||||
botGenerationDetails.playerLevel,
|
botGenerationDetails.playerLevel,
|
||||||
botGenerationDetails.botRelativeLevelDeltaMin,
|
botGenerationDetails.botRelativeLevelDeltaMin,
|
||||||
levelDetails,
|
levelDetails,
|
||||||
expTable);
|
expTable,
|
||||||
|
);
|
||||||
|
|
||||||
// Get random level based on the exp table.
|
// Get random level based on the exp table.
|
||||||
let exp = 0;
|
let exp = 0;
|
||||||
|
@ -341,7 +341,6 @@ export class BotLootGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
this.addRequiredChildItemsToParent(itemToAddTemplate, itemWithChildrenToAdd, isPmc);
|
this.addRequiredChildItemsToParent(itemToAddTemplate, itemWithChildrenToAdd, isPmc);
|
||||||
|
|
||||||
// Attempt to add item to container(s)
|
// Attempt to add item to container(s)
|
||||||
@ -359,7 +358,9 @@ export class BotLootGenerator
|
|||||||
if (itemAddedResult === ItemAddedResult.NO_CONTAINERS)
|
if (itemAddedResult === ItemAddedResult.NO_CONTAINERS)
|
||||||
{
|
{
|
||||||
// Bot has no container to put item in, exit
|
// Bot has no container to put item in, exit
|
||||||
this.logger.debug(`Unable to add: ${totalItemCount} items to bot as it lacks a container to include them`);
|
this.logger.debug(
|
||||||
|
`Unable to add: ${totalItemCount} items to bot as it lacks a container to include them`,
|
||||||
|
);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -367,7 +368,11 @@ export class BotLootGenerator
|
|||||||
if (fitItemIntoContainerAttempts >= 4)
|
if (fitItemIntoContainerAttempts >= 4)
|
||||||
{
|
{
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Failed to place item ${i} of ${totalItemCount} items into ${botRole} containers: ${equipmentSlots.join(",")}. Tried ${fitItemIntoContainerAttempts} times, reason: ${ItemAddedResult[itemAddedResult]}, skipping`,
|
`Failed to place item ${i} of ${totalItemCount} items into ${botRole} containers: ${
|
||||||
|
equipmentSlots.join(",")
|
||||||
|
}. Tried ${fitItemIntoContainerAttempts} times, reason: ${
|
||||||
|
ItemAddedResult[itemAddedResult]
|
||||||
|
}, skipping`,
|
||||||
);
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
@ -399,7 +404,11 @@ export class BotLootGenerator
|
|||||||
* @param itemToAddChildrenTo Item to add children to
|
* @param itemToAddChildrenTo Item to add children to
|
||||||
* @param isPmc Is the item being generated for a pmc (affects money/ammo stack sizes)
|
* @param isPmc Is the item being generated for a pmc (affects money/ammo stack sizes)
|
||||||
*/
|
*/
|
||||||
protected addRequiredChildItemsToParent(itemToAddTemplate: ITemplateItem, itemToAddChildrenTo: Item[], isPmc: boolean): void
|
protected addRequiredChildItemsToParent(
|
||||||
|
itemToAddTemplate: ITemplateItem,
|
||||||
|
itemToAddChildrenTo: Item[],
|
||||||
|
isPmc: boolean,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
// Fill ammo box
|
// Fill ammo box
|
||||||
if (this.itemHelper.isOfBaseclass(itemToAddTemplate._id, BaseClasses.AMMO_BOX))
|
if (this.itemHelper.isOfBaseclass(itemToAddTemplate._id, BaseClasses.AMMO_BOX))
|
||||||
@ -477,7 +486,11 @@ export class BotLootGenerator
|
|||||||
|
|
||||||
if (result !== ItemAddedResult.SUCCESS)
|
if (result !== ItemAddedResult.SUCCESS)
|
||||||
{
|
{
|
||||||
this.logger.debug(`Failed to add additional weapon ${generatedWeapon.weapon[0]._id} to bot backpack, reason: ${ItemAddedResult[result]}`);
|
this.logger.debug(
|
||||||
|
`Failed to add additional weapon ${generatedWeapon.weapon[0]._id} to bot backpack, reason: ${
|
||||||
|
ItemAddedResult[result]
|
||||||
|
}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -631,7 +644,10 @@ export class BotLootGenerator
|
|||||||
{
|
{
|
||||||
const randomSize = itemTemplate._props.StackMaxSize === 1
|
const randomSize = itemTemplate._props.StackMaxSize === 1
|
||||||
? 1
|
? 1
|
||||||
: this.randomUtil.getInt(itemTemplate._props.StackMinRandom, Math.min(itemTemplate._props.StackMaxRandom, 60));
|
: this.randomUtil.getInt(
|
||||||
|
itemTemplate._props.StackMinRandom,
|
||||||
|
Math.min(itemTemplate._props.StackMaxRandom, 60),
|
||||||
|
);
|
||||||
|
|
||||||
if (!ammoItem.upd)
|
if (!ammoItem.upd)
|
||||||
{
|
{
|
||||||
|
@ -212,7 +212,7 @@ export class BotWeaponGenerator
|
|||||||
)
|
)
|
||||||
{
|
{
|
||||||
// Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001
|
// Guns have variety of possible Chamber ids, patron_in_weapon/patron_in_weapon_000/patron_in_weapon_001
|
||||||
const chamberSlotNames = weaponItemTemplate._props.Chambers.map(x => x._name);
|
const chamberSlotNames = weaponItemTemplate._props.Chambers.map((x) => x._name);
|
||||||
this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames);
|
this.addCartridgeToChamber(weaponWithModsArray, ammoTpl, chamberSlotNames);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -311,7 +311,10 @@ export class BotWeaponGenerator
|
|||||||
{
|
{
|
||||||
// Invalid weapon generated, fallback to preset
|
// Invalid weapon generated, fallback to preset
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
this.localisationService.getText("bot-weapon_generated_incorrect_using_default", `${weaponTpl} ${itemTemplate._name}`),
|
this.localisationService.getText(
|
||||||
|
"bot-weapon_generated_incorrect_using_default",
|
||||||
|
`${weaponTpl} ${itemTemplate._name}`,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
const weaponMods = [];
|
const weaponMods = [];
|
||||||
|
|
||||||
@ -364,10 +367,12 @@ export class BotWeaponGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over required slots in db item, check mod exists for that slot
|
// Iterate over required slots in db item, check mod exists for that slot
|
||||||
for (const modSlotTemplate of modTemplate._props.Slots.filter(slot => slot._required))
|
for (const modSlotTemplate of modTemplate._props.Slots.filter((slot) => slot._required))
|
||||||
{
|
{
|
||||||
const slotName = modSlotTemplate._name;
|
const slotName = modSlotTemplate._name;
|
||||||
const weaponSlotItem = weaponItemArray.find((weaponItem) => weaponItem.parentId === mod._id && weaponItem.slotId === slotName);
|
const weaponSlotItem = weaponItemArray.find((weaponItem) =>
|
||||||
|
weaponItem.parentId === mod._id && weaponItem.slotId === slotName
|
||||||
|
);
|
||||||
if (!weaponSlotItem)
|
if (!weaponSlotItem)
|
||||||
{
|
{
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
@ -547,7 +552,10 @@ export class BotWeaponGenerator
|
|||||||
{
|
{
|
||||||
// Shouldn't happen
|
// Shouldn't happen
|
||||||
this.logger.warning(
|
this.logger.warning(
|
||||||
this.localisationService.getText("bot-weapon_missing_magazine_or_chamber", {weaponId: weaponTemplate._id, botRole: botRole}),
|
this.localisationService.getText("bot-weapon_missing_magazine_or_chamber", {
|
||||||
|
weaponId: weaponTemplate._id,
|
||||||
|
botRole: botRole,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -594,9 +602,10 @@ export class BotWeaponGenerator
|
|||||||
while (!chosenAmmoTpl)
|
while (!chosenAmmoTpl)
|
||||||
{
|
{
|
||||||
const possibleAmmo = this.weightedRandomHelper.getWeightedValue<string>(compatibleCartridges);
|
const possibleAmmo = this.weightedRandomHelper.getWeightedValue<string>(compatibleCartridges);
|
||||||
|
|
||||||
// Weapon has chamber but does not support cartridge
|
// Weapon has chamber but does not support cartridge
|
||||||
if (weaponTemplate._props.Chambers[0]
|
if (
|
||||||
|
weaponTemplate._props.Chambers[0]
|
||||||
&& !weaponTemplate._props.Chambers[0]._props.filters[0].Filter.includes(possibleAmmo)
|
&& !weaponTemplate._props.Chambers[0]._props.filters[0].Filter.includes(possibleAmmo)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
@ -64,7 +64,8 @@ export class FenceBaseAssortGenerator
|
|||||||
// Item base type blacklisted
|
// Item base type blacklisted
|
||||||
if (this.traderConfig.fence.blacklist.length > 0)
|
if (this.traderConfig.fence.blacklist.length > 0)
|
||||||
{
|
{
|
||||||
if (this.traderConfig.fence.blacklist.includes(rootItemDb._id)
|
if (
|
||||||
|
this.traderConfig.fence.blacklist.includes(rootItemDb._id)
|
||||||
|| this.itemHelper.isOfBaseclasses(rootItemDb._id, this.traderConfig.fence.blacklist)
|
|| this.itemHelper.isOfBaseclasses(rootItemDb._id, this.traderConfig.fence.blacklist)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -123,10 +124,7 @@ export class FenceBaseAssortGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Construct preset + mods
|
// Construct preset + mods
|
||||||
const presetAndMods: Item[] = this.itemHelper.replaceIDs(
|
const presetAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(defaultPreset._items));
|
||||||
null,
|
|
||||||
this.jsonUtil.clone(defaultPreset._items),
|
|
||||||
);
|
|
||||||
|
|
||||||
// Find root item and add some properties to it
|
// Find root item and add some properties to it
|
||||||
for (let i = 0; i < presetAndMods.length; i++)
|
for (let i = 0; i < presetAndMods.length; i++)
|
||||||
@ -156,7 +154,10 @@ export class FenceBaseAssortGenerator
|
|||||||
|
|
||||||
// Multiply weapon+mods rouble price by multipler in config
|
// Multiply weapon+mods rouble price by multipler in config
|
||||||
baseFenceAssort.barter_scheme[presetAndMods[0]._id] = [[]];
|
baseFenceAssort.barter_scheme[presetAndMods[0]._id] = [[]];
|
||||||
baseFenceAssort.barter_scheme[presetAndMods[0]._id][0][0] = { _tpl: Money.ROUBLES, count: Math.round(price) * this.traderConfig.fence.presetPriceMult };
|
baseFenceAssort.barter_scheme[presetAndMods[0]._id][0][0] = {
|
||||||
|
_tpl: Money.ROUBLES,
|
||||||
|
count: Math.round(price) * this.traderConfig.fence.presetPriceMult,
|
||||||
|
};
|
||||||
|
|
||||||
baseFenceAssort.loyal_level_items[presetAndMods[0]._id] = 1;
|
baseFenceAssort.loyal_level_items[presetAndMods[0]._id] = 1;
|
||||||
}
|
}
|
||||||
@ -177,7 +178,7 @@ export class FenceBaseAssortGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for and add required soft inserts to armors
|
// Check for and add required soft inserts to armors
|
||||||
const requiredSlots = itemDbDetails._props.Slots.filter(slot => slot._required);
|
const requiredSlots = itemDbDetails._props.Slots.filter((slot) => slot._required);
|
||||||
const hasRequiredSlots = requiredSlots.length > 0;
|
const hasRequiredSlots = requiredSlots.length > 0;
|
||||||
if (hasRequiredSlots)
|
if (hasRequiredSlots)
|
||||||
{
|
{
|
||||||
@ -199,9 +200,9 @@ export class FenceBaseAssortGenerator
|
|||||||
upd: {
|
upd: {
|
||||||
Repairable: {
|
Repairable: {
|
||||||
Durability: modItemDbDetails._props.MaxDurability,
|
Durability: modItemDbDetails._props.MaxDurability,
|
||||||
MaxDurability: modItemDbDetails._props.MaxDurability
|
MaxDurability: modItemDbDetails._props.MaxDurability,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
armor.push(mod);
|
armor.push(mod);
|
||||||
@ -209,12 +210,14 @@ export class FenceBaseAssortGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for and add plate items
|
// Check for and add plate items
|
||||||
const plateSlots = itemDbDetails._props.Slots.filter(slot => this.itemHelper.isRemovablePlateSlot(slot._name));
|
const plateSlots = itemDbDetails._props.Slots.filter((slot) =>
|
||||||
|
this.itemHelper.isRemovablePlateSlot(slot._name)
|
||||||
|
);
|
||||||
if (plateSlots.length > 0)
|
if (plateSlots.length > 0)
|
||||||
{
|
{
|
||||||
for (const plateSlot of plateSlots)
|
for (const plateSlot of plateSlots)
|
||||||
{
|
{
|
||||||
const plateTpl = plateSlot._props.filters[0].Plate
|
const plateTpl = plateSlot._props.filters[0].Plate;
|
||||||
if (!plateTpl)
|
if (!plateTpl)
|
||||||
{
|
{
|
||||||
// Bsg data lacks a default plate, skip adding mod
|
// Bsg data lacks a default plate, skip adding mod
|
||||||
@ -229,9 +232,9 @@ export class FenceBaseAssortGenerator
|
|||||||
upd: {
|
upd: {
|
||||||
Repairable: {
|
Repairable: {
|
||||||
Durability: modItemDbDetails._props.MaxDurability,
|
Durability: modItemDbDetails._props.MaxDurability,
|
||||||
MaxDurability: modItemDbDetails._props.MaxDurability
|
MaxDurability: modItemDbDetails._props.MaxDurability,
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -247,7 +250,7 @@ export class FenceBaseAssortGenerator
|
|||||||
let price = 0;
|
let price = 0;
|
||||||
for (const item of itemWithChildren)
|
for (const item of itemWithChildren)
|
||||||
{
|
{
|
||||||
price += this.handbookHelper.getTemplatePrice(item._tpl);
|
price += this.handbookHelper.getTemplatePrice(item._tpl);
|
||||||
}
|
}
|
||||||
|
|
||||||
return price;
|
return price;
|
||||||
|
@ -1,14 +1,14 @@
|
|||||||
export interface IFilterPlateModsForSlotByLevelResult
|
export interface IFilterPlateModsForSlotByLevelResult
|
||||||
{
|
{
|
||||||
result: Result
|
result: Result;
|
||||||
plateModTpls: string[]
|
plateModTpls: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export enum Result
|
||||||
export enum Result {
|
{
|
||||||
UNKNOWN_FAILURE = -1,
|
UNKNOWN_FAILURE = -1,
|
||||||
SUCCESS = 1,
|
SUCCESS = 1,
|
||||||
NO_DEFAULT_FILTER = 2,
|
NO_DEFAULT_FILTER = 2,
|
||||||
NOT_PLATE_HOLDING_SLOT = 3,
|
NOT_PLATE_HOLDING_SLOT = 3,
|
||||||
LACKS_PLATE_WEIGHTS = 4
|
LACKS_PLATE_WEIGHTS = 4,
|
||||||
}
|
}
|
||||||
|
@ -169,7 +169,7 @@ export class LocationGenerator
|
|||||||
const staticContainerGroupData: IStaticContainer = db.locations[locationId].statics;
|
const staticContainerGroupData: IStaticContainer = db.locations[locationId].statics;
|
||||||
if (!staticContainerGroupData)
|
if (!staticContainerGroupData)
|
||||||
{
|
{
|
||||||
this.logger.warning(`Map: ${locationId} lacks a statics file, skipping container generation.`)
|
this.logger.warning(`Map: ${locationId} lacks a statics file, skipping container generation.`);
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
@ -248,7 +248,6 @@ export class LocationGenerator
|
|||||||
staticContainerCount++;
|
staticContainerCount++;
|
||||||
|
|
||||||
staticLootItemCount += containerWithLoot.template.Items.length;
|
staticLootItemCount += containerWithLoot.template.Items.length;
|
||||||
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -430,7 +429,7 @@ export class LocationGenerator
|
|||||||
itemCountToAdd,
|
itemCountToAdd,
|
||||||
this.locationConfig.allowDuplicateItemsInStaticContainers,
|
this.locationConfig.allowDuplicateItemsInStaticContainers,
|
||||||
locklist,
|
locklist,
|
||||||
).filter(x => !tplsForced.includes(x));
|
).filter((x) => !tplsForced.includes(x));
|
||||||
|
|
||||||
// Add forced loot to chosen item pool
|
// Add forced loot to chosen item pool
|
||||||
const tplsToAddToContainer = tplsForced.concat(chosenTpls);
|
const tplsToAddToContainer = tplsForced.concat(chosenTpls);
|
||||||
@ -516,7 +515,9 @@ export class LocationGenerator
|
|||||||
const countDistribution = staticLootDist[containerTypeId]?.itemcountDistribution;
|
const countDistribution = staticLootDist[containerTypeId]?.itemcountDistribution;
|
||||||
if (!countDistribution)
|
if (!countDistribution)
|
||||||
{
|
{
|
||||||
this.logger.warning(`Unable to acquire count distrubution for container: ${containerTypeId} on: ${locationName}. defaulting to 0`);
|
this.logger.warning(
|
||||||
|
`Unable to acquire count distrubution for container: ${containerTypeId} on: ${locationName}. defaulting to 0`,
|
||||||
|
);
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -603,7 +604,10 @@ export class LocationGenerator
|
|||||||
// Draw from random distribution
|
// Draw from random distribution
|
||||||
const desiredSpawnpointCount = Math.round(
|
const desiredSpawnpointCount = Math.round(
|
||||||
this.getLooseLootMultiplerForLocation(locationName)
|
this.getLooseLootMultiplerForLocation(locationName)
|
||||||
* this.randomUtil.getNormallyDistributedRandomNumber(dynamicLootDist.spawnpointCount.mean, dynamicLootDist.spawnpointCount.std),
|
* this.randomUtil.getNormallyDistributedRandomNumber(
|
||||||
|
dynamicLootDist.spawnpointCount.mean,
|
||||||
|
dynamicLootDist.spawnpointCount.std,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
// Positions not in forced but have 100% chance to spawn
|
// Positions not in forced but have 100% chance to spawn
|
||||||
@ -823,7 +827,7 @@ export class LocationGenerator
|
|||||||
{
|
{
|
||||||
const chosenItem = spawnPoint.template.Items.find((x) => x._id === chosenComposedKey);
|
const chosenItem = spawnPoint.template.Items.find((x) => x._id === chosenComposedKey);
|
||||||
const chosenTpl = chosenItem._tpl;
|
const chosenTpl = chosenItem._tpl;
|
||||||
const itemTemplate = this.itemHelper.getItem(chosenTpl)[1];
|
const itemTemplate = this.itemHelper.getItem(chosenTpl)[1];
|
||||||
|
|
||||||
// Item array to return
|
// Item array to return
|
||||||
let itemWithMods: Item[] = [];
|
let itemWithMods: Item[] = [];
|
||||||
@ -864,18 +868,19 @@ export class LocationGenerator
|
|||||||
this.locationConfig.minFillLooseMagazinePercent / 100,
|
this.locationConfig.minFillLooseMagazinePercent / 100,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
itemWithMods.push(...magazineItem);
|
itemWithMods.push(...magazineItem);
|
||||||
}
|
}
|
||||||
else if (this.itemHelper.armorItemCanHoldMods(chosenTpl))
|
else if (this.itemHelper.armorItemCanHoldMods(chosenTpl))
|
||||||
{
|
{
|
||||||
itemWithMods.push({
|
itemWithMods.push({ _id: this.objectId.generate(), _tpl: chosenTpl });
|
||||||
_id: this.objectId.generate(),
|
|
||||||
_tpl: chosenTpl,
|
|
||||||
});
|
|
||||||
if (itemTemplate._props.Slots?.length > 0)
|
if (itemTemplate._props.Slots?.length > 0)
|
||||||
{
|
{
|
||||||
itemWithMods = this.itemHelper.addChildSlotItems(itemWithMods, itemTemplate, this.locationConfig.equipmentLootSettings.modSpawnChancePercent);
|
itemWithMods = this.itemHelper.addChildSlotItems(
|
||||||
|
itemWithMods,
|
||||||
|
itemTemplate,
|
||||||
|
this.locationConfig.equipmentLootSettings.modSpawnChancePercent,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -1004,7 +1009,10 @@ export class LocationGenerator
|
|||||||
if (!rootItem)
|
if (!rootItem)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
this.localisationService.getText("location-missing_root_item", { tpl: chosenTpl, parentId: parentId }),
|
this.localisationService.getText("location-missing_root_item", {
|
||||||
|
tpl: chosenTpl,
|
||||||
|
parentId: parentId,
|
||||||
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
throw new Error(this.localisationService.getText("location-critical_error_see_log"));
|
throw new Error(this.localisationService.getText("location-critical_error_see_log"));
|
||||||
@ -1085,14 +1093,14 @@ export class LocationGenerator
|
|||||||
// We make base item above, at start of function, no need to do it here
|
// We make base item above, at start of function, no need to do it here
|
||||||
if (itemTemplate._props.Slots?.length > 0)
|
if (itemTemplate._props.Slots?.length > 0)
|
||||||
{
|
{
|
||||||
items = this.itemHelper.addChildSlotItems(items, itemTemplate, this.locationConfig.equipmentLootSettings.modSpawnChancePercent);
|
items = this.itemHelper.addChildSlotItems(
|
||||||
|
items,
|
||||||
|
itemTemplate,
|
||||||
|
this.locationConfig.equipmentLootSettings.modSpawnChancePercent,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return { items: items, width: width, height: height };
|
||||||
items: items,
|
|
||||||
width: width,
|
|
||||||
height: height
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -112,30 +112,50 @@ export class LootGenerator
|
|||||||
const itemBlacklistArray = Array.from(itemBlacklist);
|
const itemBlacklistArray = Array.from(itemBlacklist);
|
||||||
|
|
||||||
// Filter default presets to just weapons
|
// Filter default presets to just weapons
|
||||||
const randomisedWeaponPresetCount = this.randomUtil.getInt(options.weaponPresetCount.min, options.weaponPresetCount.max);
|
const randomisedWeaponPresetCount = this.randomUtil.getInt(
|
||||||
|
options.weaponPresetCount.min,
|
||||||
|
options.weaponPresetCount.max,
|
||||||
|
);
|
||||||
if (randomisedWeaponPresetCount > 0)
|
if (randomisedWeaponPresetCount > 0)
|
||||||
{
|
{
|
||||||
const weaponDefaultPresets = globalDefaultPresets.filter(preset => this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON));
|
const weaponDefaultPresets = globalDefaultPresets.filter((preset) =>
|
||||||
|
this.itemHelper.isOfBaseclass(preset._encyclopedia, BaseClasses.WEAPON)
|
||||||
|
);
|
||||||
|
|
||||||
for (let index = 0; index < randomisedWeaponPresetCount; index++)
|
for (let index = 0; index < randomisedWeaponPresetCount; index++)
|
||||||
{
|
{
|
||||||
if (!this.findAndAddRandomPresetToLoot(weaponDefaultPresets, itemTypeCounts, itemBlacklistArray, result))
|
if (
|
||||||
|
!this.findAndAddRandomPresetToLoot(weaponDefaultPresets, itemTypeCounts, itemBlacklistArray, result)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
index--;
|
index--;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
// Filter default presets to just armors and then filter again by protection level
|
// Filter default presets to just armors and then filter again by protection level
|
||||||
const randomisedArmorPresetCount = this.randomUtil.getInt(options.armorPresetCount.min, options.armorPresetCount.max);
|
const randomisedArmorPresetCount = this.randomUtil.getInt(
|
||||||
|
options.armorPresetCount.min,
|
||||||
|
options.armorPresetCount.max,
|
||||||
|
);
|
||||||
if (randomisedArmorPresetCount > 0)
|
if (randomisedArmorPresetCount > 0)
|
||||||
{
|
{
|
||||||
const armorDefaultPresets = globalDefaultPresets.filter(preset => this.itemHelper.armorItemCanHoldMods(preset._encyclopedia));
|
const armorDefaultPresets = globalDefaultPresets.filter((preset) =>
|
||||||
const levelFilteredArmorPresets = armorDefaultPresets.filter(armor => this.armorIsDesiredProtectionLevel(armor, options));
|
this.itemHelper.armorItemCanHoldMods(preset._encyclopedia)
|
||||||
|
);
|
||||||
|
const levelFilteredArmorPresets = armorDefaultPresets.filter((armor) =>
|
||||||
|
this.armorIsDesiredProtectionLevel(armor, options)
|
||||||
|
);
|
||||||
for (let index = 0; index < randomisedArmorPresetCount; index++)
|
for (let index = 0; index < randomisedArmorPresetCount; index++)
|
||||||
{
|
{
|
||||||
if (!this.findAndAddRandomPresetToLoot(levelFilteredArmorPresets, itemTypeCounts, itemBlacklistArray, result))
|
if (
|
||||||
|
!this.findAndAddRandomPresetToLoot(
|
||||||
|
levelFilteredArmorPresets,
|
||||||
|
itemTypeCounts,
|
||||||
|
itemBlacklistArray,
|
||||||
|
result,
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
index--;
|
index--;
|
||||||
}
|
}
|
||||||
@ -153,21 +173,21 @@ export class LootGenerator
|
|||||||
*/
|
*/
|
||||||
protected armorIsDesiredProtectionLevel(armor: IPreset, options: LootRequest): boolean
|
protected armorIsDesiredProtectionLevel(armor: IPreset, options: LootRequest): boolean
|
||||||
{
|
{
|
||||||
const frontPlate = armor._items.find(mod => mod?.slotId?.toLowerCase() === "front_plate");
|
const frontPlate = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "front_plate");
|
||||||
if (frontPlate)
|
if (frontPlate)
|
||||||
{
|
{
|
||||||
const plateDb = this.itemHelper.getItem(frontPlate._tpl);
|
const plateDb = this.itemHelper.getItem(frontPlate._tpl);
|
||||||
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
|
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
|
||||||
}
|
}
|
||||||
|
|
||||||
const helmetTop = armor._items.find(mod => mod?.slotId?.toLowerCase() === "helmet_top");
|
const helmetTop = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "helmet_top");
|
||||||
if (helmetTop)
|
if (helmetTop)
|
||||||
{
|
{
|
||||||
const plateDb = this.itemHelper.getItem(helmetTop._tpl);
|
const plateDb = this.itemHelper.getItem(helmetTop._tpl);
|
||||||
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
|
return options.armorLevelWhitelist.includes(Number.parseInt(plateDb[1]._props.armorClass as any));
|
||||||
}
|
}
|
||||||
|
|
||||||
const softArmorFront = armor._items.find(mod => mod?.slotId?.toLowerCase() === "soft_armor_front");
|
const softArmorFront = armor._items.find((mod) => mod?.slotId?.toLowerCase() === "soft_armor_front");
|
||||||
if (softArmorFront)
|
if (softArmorFront)
|
||||||
{
|
{
|
||||||
const plateDb = this.itemHelper.getItem(softArmorFront._tpl);
|
const plateDb = this.itemHelper.getItem(softArmorFront._tpl);
|
||||||
@ -369,10 +389,7 @@ export class LootGenerator
|
|||||||
chosenWeaponPreset = this.randomUtil.getArrayValue(this.presetHelper.getPresets(chosenWeaponTpl));
|
chosenWeaponPreset = this.randomUtil.getArrayValue(this.presetHelper.getPresets(chosenWeaponTpl));
|
||||||
}
|
}
|
||||||
|
|
||||||
const presetAndMods: Item[] = this.itemHelper.replaceIDs(
|
const presetAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(chosenWeaponPreset._items));
|
||||||
null,
|
|
||||||
this.jsonUtil.clone(chosenWeaponPreset._items),
|
|
||||||
);
|
|
||||||
this.itemHelper.remapRootItemId(presetAndMods);
|
this.itemHelper.remapRootItemId(presetAndMods);
|
||||||
|
|
||||||
// Add preset to return object
|
// Add preset to return object
|
||||||
@ -436,12 +453,7 @@ export class LootGenerator
|
|||||||
for (let index = 0; index < rewardCount; index++)
|
for (let index = 0; index < rewardCount; index++)
|
||||||
{
|
{
|
||||||
const chosenAmmoBox = this.randomUtil.getArrayValue(ammoBoxesMatchingCaliber);
|
const chosenAmmoBox = this.randomUtil.getArrayValue(ammoBoxesMatchingCaliber);
|
||||||
const ammoBoxItem: Item[] = [
|
const ammoBoxItem: Item[] = [{ _id: this.hashUtil.generate(), _tpl: chosenAmmoBox._id }];
|
||||||
{
|
|
||||||
_id: this.hashUtil.generate(),
|
|
||||||
_tpl: chosenAmmoBox._id
|
|
||||||
}
|
|
||||||
]
|
|
||||||
this.itemHelper.addCartridgesToAmmoBox(ammoBoxItem, chosenAmmoBox);
|
this.itemHelper.addCartridgesToAmmoBox(ammoBoxItem, chosenAmmoBox);
|
||||||
rewards.push(ammoBoxItem);
|
rewards.push(ammoBoxItem);
|
||||||
}
|
}
|
||||||
@ -469,14 +481,9 @@ export class LootGenerator
|
|||||||
{
|
{
|
||||||
// Choose a random item from pool
|
// Choose a random item from pool
|
||||||
const chosenRewardItem = this.randomUtil.getArrayValue(rewardItemPool);
|
const chosenRewardItem = this.randomUtil.getArrayValue(rewardItemPool);
|
||||||
const rewardItem: Item[] = [
|
const rewardItem: Item[] = [{ _id: this.hashUtil.generate(), _tpl: chosenRewardItem._id }];
|
||||||
{
|
|
||||||
_id: this.hashUtil.generate(),
|
|
||||||
_tpl: chosenRewardItem._id
|
|
||||||
}
|
|
||||||
]
|
|
||||||
|
|
||||||
rewards.push(rewardItem)
|
rewards.push(rewardItem);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -524,12 +531,9 @@ export class LootGenerator
|
|||||||
for (let index = 0; index < rewardCount; index++)
|
for (let index = 0; index < rewardCount; index++)
|
||||||
{
|
{
|
||||||
const chosenItem = this.randomUtil.drawRandomFromList(relatedItems);
|
const chosenItem = this.randomUtil.drawRandomFromList(relatedItems);
|
||||||
const item: Item[] = [{
|
const item: Item[] = [{ _id: this.hashUtil.generate(), _tpl: chosenItem[0]._id }];
|
||||||
_id: this.hashUtil.generate(),
|
|
||||||
_tpl: chosenItem[0]._id
|
|
||||||
}];
|
|
||||||
|
|
||||||
modRewards.push(item)
|
modRewards.push(item);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -552,13 +556,8 @@ export class LootGenerator
|
|||||||
const chosenRewardItemTpl = this.weightedRandomHelper.getWeightedValue<string>(
|
const chosenRewardItemTpl = this.weightedRandomHelper.getWeightedValue<string>(
|
||||||
rewardContainerDetails.rewardTplPool,
|
rewardContainerDetails.rewardTplPool,
|
||||||
);
|
);
|
||||||
const rewardItem: Item[] = [
|
const rewardItem: Item[] = [{ _id: this.hashUtil.generate(), _tpl: chosenRewardItemTpl }];
|
||||||
{
|
itemsToReturn.push(rewardItem);
|
||||||
_id: this.hashUtil.generate(),
|
|
||||||
_tpl: chosenRewardItemTpl
|
|
||||||
}
|
|
||||||
]
|
|
||||||
itemsToReturn.push(rewardItem)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return itemsToReturn;
|
return itemsToReturn;
|
||||||
|
@ -114,7 +114,7 @@ export class PlayerScavGenerator
|
|||||||
scavData.Info.Level = this.getScavLevel(existingScavData);
|
scavData.Info.Level = this.getScavLevel(existingScavData);
|
||||||
scavData.Info.Experience = this.getScavExperience(existingScavData);
|
scavData.Info.Experience = this.getScavExperience(existingScavData);
|
||||||
scavData.Quests = existingScavData.Quests ?? [];
|
scavData.Quests = existingScavData.Quests ?? [];
|
||||||
scavData.TaskConditionCounters = existingScavData.TaskConditionCounters ?? { };
|
scavData.TaskConditionCounters = existingScavData.TaskConditionCounters ?? {};
|
||||||
scavData.Notes = existingScavData.Notes ?? { Notes: [] };
|
scavData.Notes = existingScavData.Notes ?? { Notes: [] };
|
||||||
scavData.WishList = existingScavData.WishList ?? [];
|
scavData.WishList = existingScavData.WishList ?? [];
|
||||||
|
|
||||||
|
@ -75,21 +75,18 @@ export class RagfairAssortGenerator
|
|||||||
const results: Item[][] = [];
|
const results: Item[][] = [];
|
||||||
|
|
||||||
/** Get cloned items from db */
|
/** Get cloned items from db */
|
||||||
const dbItemsClone = this.itemHelper.getItems().filter(item => item._type !== "Node");
|
const dbItemsClone = this.itemHelper.getItems().filter((item) => item._type !== "Node");
|
||||||
|
|
||||||
/** Store processed preset tpls so we dont add them when procesing non-preset items */
|
/** Store processed preset tpls so we dont add them when procesing non-preset items */
|
||||||
const processedArmorItems: string[] = [];
|
const processedArmorItems: string[] = [];
|
||||||
const seasonalEventActive = this.seasonalEventService.seasonalEventEnabled();
|
const seasonalEventActive = this.seasonalEventService.seasonalEventEnabled();
|
||||||
const seasonalItemTplBlacklist = this.seasonalEventService.getInactiveSeasonalEventItems();
|
const seasonalItemTplBlacklist = this.seasonalEventService.getInactiveSeasonalEventItems();
|
||||||
|
|
||||||
const presets = this.getPresetsToAdd();
|
const presets = this.getPresetsToAdd();
|
||||||
for (const preset of presets)
|
for (const preset of presets)
|
||||||
{
|
{
|
||||||
// Update Ids and clone
|
// Update Ids and clone
|
||||||
const presetAndMods: Item[] = this.itemHelper.replaceIDs(
|
const presetAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(preset._items));
|
||||||
null,
|
|
||||||
this.jsonUtil.clone(preset._items),
|
|
||||||
);
|
|
||||||
this.itemHelper.remapRootItemId(presetAndMods);
|
this.itemHelper.remapRootItemId(presetAndMods);
|
||||||
|
|
||||||
// Add presets base item tpl to the processed list so its skipped later on when processing items
|
// Add presets base item tpl to the processed list so its skipped later on when processing items
|
||||||
@ -97,9 +94,9 @@ export class RagfairAssortGenerator
|
|||||||
|
|
||||||
presetAndMods[0].parentId = "hideout";
|
presetAndMods[0].parentId = "hideout";
|
||||||
presetAndMods[0].slotId = "hideout";
|
presetAndMods[0].slotId = "hideout";
|
||||||
presetAndMods[0].upd = { StackObjectsCount: 99999999, UnlimitedCount: true, sptPresetId: preset._id};
|
presetAndMods[0].upd = { StackObjectsCount: 99999999, UnlimitedCount: true, sptPresetId: preset._id };
|
||||||
|
|
||||||
results.push(presetAndMods);
|
results.push(presetAndMods);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (const item of dbItemsClone)
|
for (const item of dbItemsClone)
|
||||||
@ -126,7 +123,7 @@ export class RagfairAssortGenerator
|
|||||||
|
|
||||||
const ragfairAssort = this.createRagfairAssortRootItem(item._id, item._id); // tplid and id must be the same so hideout recipe rewards work
|
const ragfairAssort = this.createRagfairAssortRootItem(item._id, item._id); // tplid and id must be the same so hideout recipe rewards work
|
||||||
|
|
||||||
results.push([ragfairAssort]);
|
results.push([ragfairAssort]);
|
||||||
}
|
}
|
||||||
|
|
||||||
return results;
|
return results;
|
||||||
@ -140,8 +137,8 @@ export class RagfairAssortGenerator
|
|||||||
protected getPresetsToAdd(): IPreset[]
|
protected getPresetsToAdd(): IPreset[]
|
||||||
{
|
{
|
||||||
return (this.ragfairConfig.dynamic.showDefaultPresetsOnly)
|
return (this.ragfairConfig.dynamic.showDefaultPresetsOnly)
|
||||||
? Object.values(this.presetHelper.getDefaultPresets())
|
? Object.values(this.presetHelper.getDefaultPresets())
|
||||||
: this.presetHelper.getAllPresets()
|
: this.presetHelper.getAllPresets();
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -288,7 +288,8 @@ export class RagfairOfferGenerator
|
|||||||
if (this.ragfairServerHelper.isPlayer(userID))
|
if (this.ragfairServerHelper.isPlayer(userID))
|
||||||
{
|
{
|
||||||
// Player offer = current time + offerDurationTimeInHour;
|
// Player offer = current time + offerDurationTimeInHour;
|
||||||
const offerDurationTimeHours = this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour;
|
const offerDurationTimeHours =
|
||||||
|
this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour;
|
||||||
return this.timeUtil.getTimestamp() + Math.round(offerDurationTimeHours * TimeUtil.ONE_HOUR_AS_SECONDS);
|
return this.timeUtil.getTimestamp() + Math.round(offerDurationTimeHours * TimeUtil.ONE_HOUR_AS_SECONDS);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -357,7 +358,10 @@ export class RagfairOfferGenerator
|
|||||||
// Armor presets can hold plates above the allowed flea level, remove if necessary
|
// Armor presets can hold plates above the allowed flea level, remove if necessary
|
||||||
if (isPreset && this.ragfairConfig.dynamic.blacklist.enableBsgList)
|
if (isPreset && this.ragfairConfig.dynamic.blacklist.enableBsgList)
|
||||||
{
|
{
|
||||||
this.removeBannedPlatesFromPreset(assortItemWithChildren, this.ragfairConfig.dynamic.blacklist.armorPlateMaxProtectionLevel);
|
this.removeBannedPlatesFromPreset(
|
||||||
|
assortItemWithChildren,
|
||||||
|
this.ragfairConfig.dynamic.blacklist.armorPlateMaxProtectionLevel,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get number of offers to create
|
// Get number of offers to create
|
||||||
@ -375,11 +379,13 @@ export class RagfairOfferGenerator
|
|||||||
// Presets get unique id generated during getPresetItems() earlier + would require regenerating all children to match
|
// Presets get unique id generated during getPresetItems() earlier + would require regenerating all children to match
|
||||||
assortItemWithChildren[0]._id = this.hashUtil.generate();
|
assortItemWithChildren[0]._id = this.hashUtil.generate();
|
||||||
}
|
}
|
||||||
|
|
||||||
delete assortItemWithChildren[0].parentId;
|
delete assortItemWithChildren[0].parentId;
|
||||||
delete assortItemWithChildren[0].slotId;
|
delete assortItemWithChildren[0].slotId;
|
||||||
|
|
||||||
assortSingleOfferProcesses.push(this.createSingleOfferForItem(assortItemWithChildren, isPreset, itemDetails));
|
assortSingleOfferProcesses.push(
|
||||||
|
this.createSingleOfferForItem(assortItemWithChildren, isPreset, itemDetails),
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
await Promise.all(assortSingleOfferProcesses);
|
await Promise.all(assortSingleOfferProcesses);
|
||||||
@ -399,7 +405,9 @@ export class RagfairOfferGenerator
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
const plateSlots = presetWithChildren.filter(item => this.itemHelper.getRemovablePlateSlotIds().includes(item.slotId?.toLowerCase()));
|
const plateSlots = presetWithChildren.filter((item) =>
|
||||||
|
this.itemHelper.getRemovablePlateSlotIds().includes(item.slotId?.toLowerCase())
|
||||||
|
);
|
||||||
if (plateSlots.length === 0)
|
if (plateSlots.length === 0)
|
||||||
{
|
{
|
||||||
// Has no plate slots e.g. "left_side_plate", exit
|
// Has no plate slots e.g. "left_side_plate", exit
|
||||||
@ -409,7 +417,8 @@ export class RagfairOfferGenerator
|
|||||||
let removedPlate = false;
|
let removedPlate = false;
|
||||||
for (const plateSlot of plateSlots)
|
for (const plateSlot of plateSlots)
|
||||||
{
|
{
|
||||||
const plateArmorLevel = Number.parseInt(<string>this.itemHelper.getItem(plateSlot._tpl)[1]._props.armorClass) ?? 0;
|
const plateArmorLevel =
|
||||||
|
Number.parseInt(<string>this.itemHelper.getItem(plateSlot._tpl)[1]._props.armorClass) ?? 0;
|
||||||
if (plateArmorLevel > plateProtectionLimit)
|
if (plateArmorLevel > plateProtectionLimit)
|
||||||
{
|
{
|
||||||
presetWithChildren.splice(presetWithChildren.indexOf(plateSlot), 1);
|
presetWithChildren.splice(presetWithChildren.indexOf(plateSlot), 1);
|
||||||
@ -417,7 +426,7 @@ export class RagfairOfferGenerator
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
return removedPlate
|
return removedPlate;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -434,13 +443,19 @@ export class RagfairOfferGenerator
|
|||||||
): Promise<void>
|
): Promise<void>
|
||||||
{
|
{
|
||||||
// Set stack size to random value
|
// Set stack size to random value
|
||||||
itemWithChildren[0].upd.StackObjectsCount = this.ragfairServerHelper.calculateDynamicStackCount(itemWithChildren[0]._tpl, isPreset);
|
itemWithChildren[0].upd.StackObjectsCount = this.ragfairServerHelper.calculateDynamicStackCount(
|
||||||
|
itemWithChildren[0]._tpl,
|
||||||
|
isPreset,
|
||||||
|
);
|
||||||
|
|
||||||
const isBarterOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.barter.chancePercent);
|
const isBarterOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.barter.chancePercent);
|
||||||
const isPackOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.pack.chancePercent)
|
const isPackOffer = this.randomUtil.getChance100(this.ragfairConfig.dynamic.pack.chancePercent)
|
||||||
&& !isBarterOffer
|
&& !isBarterOffer
|
||||||
&& itemWithChildren.length === 1
|
&& itemWithChildren.length === 1
|
||||||
&& this.itemHelper.isOfBaseclasses(itemWithChildren[0]._tpl, this.ragfairConfig.dynamic.pack.itemTypeWhitelist);
|
&& this.itemHelper.isOfBaseclasses(
|
||||||
|
itemWithChildren[0]._tpl,
|
||||||
|
this.ragfairConfig.dynamic.pack.itemTypeWhitelist,
|
||||||
|
);
|
||||||
const randomUserId = this.hashUtil.generate();
|
const randomUserId = this.hashUtil.generate();
|
||||||
|
|
||||||
let barterScheme: IBarterScheme[];
|
let barterScheme: IBarterScheme[];
|
||||||
@ -614,22 +629,29 @@ export class RagfairOfferGenerator
|
|||||||
* @param itemWithMods Item to adjust condition details of
|
* @param itemWithMods Item to adjust condition details of
|
||||||
* @param itemDetails db item details of first item in array
|
* @param itemDetails db item details of first item in array
|
||||||
*/
|
*/
|
||||||
protected randomiseItemCondition(conditionSettingsId: string, itemWithMods: Item[], itemDetails: ITemplateItem): void
|
protected randomiseItemCondition(
|
||||||
|
conditionSettingsId: string,
|
||||||
|
itemWithMods: Item[],
|
||||||
|
itemDetails: ITemplateItem,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
const rootItem = itemWithMods[0];
|
const rootItem = itemWithMods[0];
|
||||||
|
|
||||||
const itemConditionValues = this.ragfairConfig.dynamic.condition[conditionSettingsId];
|
const itemConditionValues = this.ragfairConfig.dynamic.condition[conditionSettingsId];
|
||||||
const multiplier = this.randomUtil.getFloat(
|
const multiplier = this.randomUtil.getFloat(itemConditionValues.min, itemConditionValues.max);
|
||||||
itemConditionValues.min,
|
|
||||||
itemConditionValues.max,
|
|
||||||
);
|
|
||||||
|
|
||||||
// Randomise armor + plates + armor related things
|
// Randomise armor + plates + armor related things
|
||||||
if (this.itemHelper.armorItemCanHoldMods(rootItem._tpl)
|
if (
|
||||||
|| this.itemHelper.isOfBaseclasses(rootItem._tpl, [BaseClasses.ARMOR_PLATE, BaseClasses.ARMORED_EQUIPMENT]))
|
this.itemHelper.armorItemCanHoldMods(rootItem._tpl)
|
||||||
|
|| this.itemHelper.isOfBaseclasses(rootItem._tpl, [BaseClasses.ARMOR_PLATE, BaseClasses.ARMORED_EQUIPMENT])
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// Chance to not adjust armor
|
// Chance to not adjust armor
|
||||||
if (!this.randomUtil.getChance100(this.ragfairConfig.dynamic.condition[BaseClasses.ARMORED_EQUIPMENT].conditionChance * 100))
|
if (
|
||||||
|
!this.randomUtil.getChance100(
|
||||||
|
this.ragfairConfig.dynamic.condition[BaseClasses.ARMORED_EQUIPMENT].conditionChance * 100,
|
||||||
|
)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -637,18 +659,17 @@ export class RagfairOfferGenerator
|
|||||||
this.randomiseArmorDurabilityValues(itemWithMods);
|
this.randomiseArmorDurabilityValues(itemWithMods);
|
||||||
|
|
||||||
// Add hits to visor
|
// Add hits to visor
|
||||||
const visorMod = itemWithMods.find(item => item.parentId === BaseClasses.ARMORED_EQUIPMENT && item.slotId === "mod_equipment_000");
|
const visorMod = itemWithMods.find((item) =>
|
||||||
if (this.randomUtil.getChance100(25)
|
item.parentId === BaseClasses.ARMORED_EQUIPMENT && item.slotId === "mod_equipment_000"
|
||||||
&& visorMod)
|
);
|
||||||
|
if (this.randomUtil.getChance100(25) && visorMod)
|
||||||
{
|
{
|
||||||
if (!visorMod.upd)
|
if (!visorMod.upd)
|
||||||
{
|
{
|
||||||
visorMod.upd = {};
|
visorMod.upd = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
visorMod.upd.FaceShield = {
|
visorMod.upd.FaceShield = { Hits: this.randomUtil.getInt(1, 3) };
|
||||||
Hits: this.randomUtil.getInt(1,3)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -673,7 +694,8 @@ export class RagfairOfferGenerator
|
|||||||
if (rootItem.upd.Key && itemDetails._props.MaximumNumberOfUsage > 1)
|
if (rootItem.upd.Key && itemDetails._props.MaximumNumberOfUsage > 1)
|
||||||
{
|
{
|
||||||
// randomize key uses
|
// randomize key uses
|
||||||
rootItem.upd.Key.NumberOfUsages = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - multiplier)) || 0;
|
rootItem.upd.Key.NumberOfUsages = Math.round(itemDetails._props.MaximumNumberOfUsage * (1 - multiplier))
|
||||||
|
|| 0;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -752,22 +774,26 @@ export class RagfairOfferGenerator
|
|||||||
// Store mod types durabiltiy multiplier for later use in current/max durability value calculation
|
// Store mod types durabiltiy multiplier for later use in current/max durability value calculation
|
||||||
if (!childMultiplerValues[itemDbDetails._parent])
|
if (!childMultiplerValues[itemDbDetails._parent])
|
||||||
{
|
{
|
||||||
childMultiplerValues[itemDbDetails._parent] = this.randomUtil.getFloat(
|
childMultiplerValues[itemDbDetails._parent] =
|
||||||
itemDurabilityConfigDict[itemDbDetails._parent].min,
|
this.randomUtil.getFloat(
|
||||||
itemDurabilityConfigDict[itemDbDetails._parent].max,
|
itemDurabilityConfigDict[itemDbDetails._parent].min,
|
||||||
) / itemDurabilityConfigDict[itemDbDetails._parent].max;
|
itemDurabilityConfigDict[itemDbDetails._parent].max,
|
||||||
|
) / itemDurabilityConfigDict[itemDbDetails._parent].max;
|
||||||
}
|
}
|
||||||
|
|
||||||
const modMultipler = childMultiplerValues[itemDbDetails._parent];
|
const modMultipler = childMultiplerValues[itemDbDetails._parent];
|
||||||
const maxDurability = Math.round(
|
const maxDurability = Math.round(
|
||||||
this.randomUtil.getFloat(itemDbDetails._props.MaxDurability * this.randomUtil.getFloat(modMultipler, 1), itemDbDetails._props.MaxDurability),
|
this.randomUtil.getFloat(
|
||||||
|
itemDbDetails._props.MaxDurability * this.randomUtil.getFloat(modMultipler, 1),
|
||||||
|
itemDbDetails._props.MaxDurability,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
const durability = Math.round(
|
const durability = Math.round(
|
||||||
this.randomUtil.getFloat(maxDurability * this.randomUtil.getFloat(modMultipler, 1), maxDurability),
|
this.randomUtil.getFloat(maxDurability * this.randomUtil.getFloat(modMultipler, 1), maxDurability),
|
||||||
);
|
);
|
||||||
item.upd.Repairable = {
|
item.upd.Repairable = {
|
||||||
Durability: durability || 1, // Never let value become 0
|
Durability: durability || 1, // Never let value become 0
|
||||||
MaxDurability: maxDurability
|
MaxDurability: maxDurability,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -896,7 +922,11 @@ export class RagfairOfferGenerator
|
|||||||
* @param multipler What to multiply the resulting price by
|
* @param multipler What to multiply the resulting price by
|
||||||
* @returns Barter scheme for offer
|
* @returns Barter scheme for offer
|
||||||
*/
|
*/
|
||||||
protected createCurrencyBarterScheme(offerWithChildren: Item[], isPackOffer: boolean, multipler = 1): IBarterScheme[]
|
protected createCurrencyBarterScheme(
|
||||||
|
offerWithChildren: Item[],
|
||||||
|
isPackOffer: boolean,
|
||||||
|
multipler = 1,
|
||||||
|
): IBarterScheme[]
|
||||||
{
|
{
|
||||||
const currency = this.ragfairServerHelper.getDynamicOfferCurrency();
|
const currency = this.ragfairServerHelper.getDynamicOfferCurrency();
|
||||||
const price = this.ragfairPriceService.getDynamicOfferPriceForOffer(offerWithChildren, currency, isPackOffer)
|
const price = this.ragfairPriceService.getDynamicOfferPriceForOffer(offerWithChildren, currency, isPackOffer)
|
||||||
|
@ -9,7 +9,12 @@ import { RepeatableQuestHelper } from "@spt-aki/helpers/RepeatableQuestHelper";
|
|||||||
import { Exit, ILocationBase } from "@spt-aki/models/eft/common/ILocationBase";
|
import { Exit, ILocationBase } from "@spt-aki/models/eft/common/ILocationBase";
|
||||||
import { TraderInfo } from "@spt-aki/models/eft/common/tables/IBotBase";
|
import { TraderInfo } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||||
import { IQuestCondition, IQuestConditionCounterCondition, IQuestReward, IQuestRewards } from "@spt-aki/models/eft/common/tables/IQuest";
|
import {
|
||||||
|
IQuestCondition,
|
||||||
|
IQuestConditionCounterCondition,
|
||||||
|
IQuestReward,
|
||||||
|
IQuestRewards,
|
||||||
|
} from "@spt-aki/models/eft/common/tables/IQuest";
|
||||||
import { IRepeatableQuest } from "@spt-aki/models/eft/common/tables/IRepeatableQuests";
|
import { IRepeatableQuest } from "@spt-aki/models/eft/common/tables/IRepeatableQuests";
|
||||||
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
||||||
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
|
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
|
||||||
@ -292,11 +297,15 @@ export class RepeatableQuestGenerator
|
|||||||
// Filter out close range weapons from far distance requirement
|
// Filter out close range weapons from far distance requirement
|
||||||
if (distance > 50)
|
if (distance > 50)
|
||||||
{
|
{
|
||||||
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter(category => ["Shotgun", "Pistol"].includes(category.key));
|
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter((category) =>
|
||||||
|
["Shotgun", "Pistol"].includes(category.key)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else if (distance < 20) // Filter out far range weapons from close distance requirement
|
else if (distance < 20)
|
||||||
{
|
{ // Filter out far range weapons from close distance requirement
|
||||||
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter(category => ["MarksmanRifle", "DMR"].includes(category.key));
|
weaponCategoryRequirementConfig = weaponCategoryRequirementConfig.filter((category) =>
|
||||||
|
["MarksmanRifle", "DMR"].includes(category.key)
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Pick a weighted weapon category
|
// Pick a weighted weapon category
|
||||||
@ -418,7 +427,7 @@ export class RepeatableQuestGenerator
|
|||||||
id: this.objectId.generate(),
|
id: this.objectId.generate(),
|
||||||
dynamicLocale: true,
|
dynamicLocale: true,
|
||||||
target: location,
|
target: location,
|
||||||
conditionType: "Location"
|
conditionType: "Location",
|
||||||
};
|
};
|
||||||
|
|
||||||
return propsObject;
|
return propsObject;
|
||||||
@ -477,7 +486,7 @@ export class RepeatableQuestGenerator
|
|||||||
if (allowedWeaponCategory?.length > 0)
|
if (allowedWeaponCategory?.length > 0)
|
||||||
{
|
{
|
||||||
// TODO - fix - does weaponCategories exist?
|
// TODO - fix - does weaponCategories exist?
|
||||||
//killConditionProps.weaponCategories = [allowedWeaponCategory];
|
// killConditionProps.weaponCategories = [allowedWeaponCategory];
|
||||||
}
|
}
|
||||||
|
|
||||||
return killConditionProps;
|
return killConditionProps;
|
||||||
@ -568,8 +577,8 @@ export class RepeatableQuestGenerator
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Draw items to ask player to retrieve
|
// Draw items to ask player to retrieve
|
||||||
let isAmmo = 0
|
let isAmmo = 0;
|
||||||
const randomNumbersUsed = [];
|
const randomNumbersUsed = [];
|
||||||
for (let i = 0; i < distinctItemsToRetrieveCount; i++)
|
for (let i = 0; i < distinctItemsToRetrieveCount; i++)
|
||||||
{
|
{
|
||||||
let randomNumber = this.randomUtil.randInt(itemSelection.length);
|
let randomNumber = this.randomUtil.randInt(itemSelection.length);
|
||||||
@ -694,7 +703,8 @@ export class RepeatableQuestGenerator
|
|||||||
): IRepeatableQuest
|
): IRepeatableQuest
|
||||||
{
|
{
|
||||||
const explorationConfig = repeatableConfig.questConfig.Exploration;
|
const explorationConfig = repeatableConfig.questConfig.Exploration;
|
||||||
const requiresSpecificExtract = Math.random() < repeatableConfig.questConfig.Exploration.specificExits.probability;
|
const requiresSpecificExtract =
|
||||||
|
Math.random() < repeatableConfig.questConfig.Exploration.specificExits.probability;
|
||||||
|
|
||||||
if (Object.keys(questTypePool.pool.Exploration.locations).length === 0)
|
if (Object.keys(questTypePool.pool.Exploration.locations).length === 0)
|
||||||
{
|
{
|
||||||
@ -731,7 +741,7 @@ export class RepeatableQuestGenerator
|
|||||||
dynamicLocale: true,
|
dynamicLocale: true,
|
||||||
target: locationTarget,
|
target: locationTarget,
|
||||||
};
|
};
|
||||||
|
|
||||||
quest.conditions.AvailableForFinish[0].counter.id = this.objectId.generate();
|
quest.conditions.AvailableForFinish[0].counter.id = this.objectId.generate();
|
||||||
quest.conditions.AvailableForFinish[0].counter.conditions = [exitStatusCondition, locationCondition];
|
quest.conditions.AvailableForFinish[0].counter.conditions = [exitStatusCondition, locationCondition];
|
||||||
quest.conditions.AvailableForFinish[0].value = numExtracts;
|
quest.conditions.AvailableForFinish[0].value = numExtracts;
|
||||||
@ -742,27 +752,30 @@ export class RepeatableQuestGenerator
|
|||||||
{
|
{
|
||||||
// Filter by whitelist, it's also possible that the field "PassageRequirement" does not exist (e.g. Shoreline)
|
// Filter by whitelist, it's also possible that the field "PassageRequirement" does not exist (e.g. Shoreline)
|
||||||
let mapExits = this.getLocationExitsForSide(locationKey, repeatableConfig.side);
|
let mapExits = this.getLocationExitsForSide(locationKey, repeatableConfig.side);
|
||||||
|
|
||||||
// Exclude scav coop exits when choosing pmc exit
|
// Exclude scav coop exits when choosing pmc exit
|
||||||
if (repeatableConfig.side === "Pmc")
|
if (repeatableConfig.side === "Pmc")
|
||||||
{
|
{
|
||||||
mapExits = mapExits.filter(exit => exit.PassageRequirement !== "ScavCooperation")
|
mapExits = mapExits.filter((exit) => exit.PassageRequirement !== "ScavCooperation");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Only get exits that have a greater than 0% chance to spawn
|
// Only get exits that have a greater than 0% chance to spawn
|
||||||
const exitPool = mapExits.filter(exit => exit.Chance > 0);
|
const exitPool = mapExits.filter((exit) => exit.Chance > 0);
|
||||||
|
|
||||||
// Exclude exits with a requirement to leave (e.g. car extracts)
|
// Exclude exits with a requirement to leave (e.g. car extracts)
|
||||||
const possibleExits = exitPool.filter((exit) =>
|
const possibleExits = exitPool.filter((
|
||||||
(!("PassageRequirement" in exit)
|
exit,
|
||||||
|| repeatableConfig.questConfig.Exploration.specificExits.passageRequirementWhitelist.includes(
|
) => (!("PassageRequirement" in exit)
|
||||||
exit.PassageRequirement
|
|| repeatableConfig.questConfig.Exploration.specificExits.passageRequirementWhitelist.includes(
|
||||||
))
|
exit.PassageRequirement,
|
||||||
|
))
|
||||||
);
|
);
|
||||||
|
|
||||||
if (possibleExits.length === 0)
|
if (possibleExits.length === 0)
|
||||||
{
|
{
|
||||||
this.logger.error(`Unable to choose specific exit on map: ${locationKey}, Possible exit pool was empty`);
|
this.logger.error(
|
||||||
|
`Unable to choose specific exit on map: ${locationKey}, Possible exit pool was empty`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -792,13 +805,12 @@ export class RepeatableQuestGenerator
|
|||||||
protected getLocationExitsForSide(locationKey: string, playerSide: string): Exit[]
|
protected getLocationExitsForSide(locationKey: string, playerSide: string): Exit[]
|
||||||
{
|
{
|
||||||
const mapBase = this.databaseServer.getTables().locations[locationKey.toLowerCase()].base as ILocationBase;
|
const mapBase = this.databaseServer.getTables().locations[locationKey.toLowerCase()].base as ILocationBase;
|
||||||
|
|
||||||
const infilPointsOfSameSide = new Set<string>();
|
const infilPointsOfSameSide = new Set<string>();
|
||||||
for (const spawnPoint of mapBase.SpawnPointParams)
|
for (const spawnPoint of mapBase.SpawnPointParams)
|
||||||
{
|
{
|
||||||
// Same side, add infil to list
|
// Same side, add infil to list
|
||||||
if (spawnPoint.Sides.includes(playerSide)
|
if (spawnPoint.Sides.includes(playerSide) || spawnPoint.Sides.includes("All"))
|
||||||
|| spawnPoint.Sides.includes("All"))
|
|
||||||
{
|
{
|
||||||
// Has specific start location
|
// Has specific start location
|
||||||
if (spawnPoint.Infiltration.length > 0)
|
if (spawnPoint.Infiltration.length > 0)
|
||||||
@ -811,7 +823,9 @@ export class RepeatableQuestGenerator
|
|||||||
// use list of allowed infils to figure out side of exits
|
// use list of allowed infils to figure out side of exits
|
||||||
const infilPointsArray = Array.from(infilPointsOfSameSide);
|
const infilPointsArray = Array.from(infilPointsOfSameSide);
|
||||||
|
|
||||||
return mapBase.exits.filter(exit => exit.EntryPoints.split(",").some(entryPoint => infilPointsArray.includes(entryPoint)));
|
return mapBase.exits.filter((exit) =>
|
||||||
|
exit.EntryPoints.split(",").some((entryPoint) => infilPointsArray.includes(entryPoint))
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
protected generatePickupQuest(
|
protected generatePickupQuest(
|
||||||
@ -838,16 +852,16 @@ export class RepeatableQuestGenerator
|
|||||||
findCondition.target = [itemTypeToFetchWithCount.itemType];
|
findCondition.target = [itemTypeToFetchWithCount.itemType];
|
||||||
findCondition.value = itemCountToFetch;
|
findCondition.value = itemCountToFetch;
|
||||||
|
|
||||||
const counterCreatorCondition = quest.conditions.AvailableForFinish.find((x) => x.conditionType === "CounterCreator");
|
const counterCreatorCondition = quest.conditions.AvailableForFinish.find((x) =>
|
||||||
|
x.conditionType === "CounterCreator"
|
||||||
|
);
|
||||||
// const locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location");
|
// const locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location");
|
||||||
// (locationCondition._props as ILocationConditionProps).target = [...locationTarget];
|
// (locationCondition._props as ILocationConditionProps).target = [...locationTarget];
|
||||||
|
|
||||||
const equipmentCondition = counterCreatorCondition.counter.conditions.find((x) =>
|
const equipmentCondition = counterCreatorCondition.counter.conditions.find((x) =>
|
||||||
x.conditionType === "Equipment"
|
x.conditionType === "Equipment"
|
||||||
);
|
);
|
||||||
equipmentCondition.equipmentInclusive = [[
|
equipmentCondition.equipmentInclusive = [[itemTypeToFetchWithCount.itemType]];
|
||||||
itemTypeToFetchWithCount.itemType,
|
|
||||||
]];
|
|
||||||
|
|
||||||
// Add rewards
|
// Add rewards
|
||||||
quest.rewards = this.generateReward(pmcLevel, 1, traderId, repeatableConfig, pickupConfig);
|
quest.rewards = this.generateReward(pmcLevel, 1, traderId, repeatableConfig, pickupConfig);
|
||||||
@ -874,12 +888,7 @@ export class RepeatableQuestGenerator
|
|||||||
*/
|
*/
|
||||||
protected generateExplorationExitCondition(exit: Exit): IQuestConditionCounterCondition
|
protected generateExplorationExitCondition(exit: Exit): IQuestConditionCounterCondition
|
||||||
{
|
{
|
||||||
return {
|
return { conditionType: "ExitName", exitName: exit.Name, id: this.objectId.generate(), dynamicLocale: true };
|
||||||
conditionType: "ExitName",
|
|
||||||
exitName: exit.Name,
|
|
||||||
id: this.objectId.generate(),
|
|
||||||
dynamicLocale: true,
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -951,11 +960,7 @@ export class RepeatableQuestGenerator
|
|||||||
let roublesBudget = rewardRoubles;
|
let roublesBudget = rewardRoubles;
|
||||||
let rewardItemPool = this.chooseRewardItemsWithinBudget(repeatableConfig, roublesBudget, traderId);
|
let rewardItemPool = this.chooseRewardItemsWithinBudget(repeatableConfig, roublesBudget, traderId);
|
||||||
|
|
||||||
const rewards: IQuestRewards = {
|
const rewards: IQuestRewards = { Started: [], Success: [], Fail: [] };
|
||||||
Started: [],
|
|
||||||
Success: [],
|
|
||||||
Fail: [],
|
|
||||||
};
|
|
||||||
|
|
||||||
let rewardIndex = 0;
|
let rewardIndex = 0;
|
||||||
// Add xp reward
|
// Add xp reward
|
||||||
@ -970,7 +975,11 @@ export class RepeatableQuestGenerator
|
|||||||
{
|
{
|
||||||
// convert to equivalent dollars
|
// convert to equivalent dollars
|
||||||
rewards.Success.push(
|
rewards.Success.push(
|
||||||
this.generateRewardItem(Money.EUROS, this.handbookHelper.fromRUB(rewardRoubles, Money.EUROS), rewardIndex),
|
this.generateRewardItem(
|
||||||
|
Money.EUROS,
|
||||||
|
this.handbookHelper.fromRUB(rewardRoubles, Money.EUROS),
|
||||||
|
rewardIndex,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
@ -980,14 +989,19 @@ export class RepeatableQuestGenerator
|
|||||||
rewardIndex++;
|
rewardIndex++;
|
||||||
|
|
||||||
const traderWhitelistDetails = repeatableConfig.traderWhitelist.find((x) => x.traderId === traderId);
|
const traderWhitelistDetails = repeatableConfig.traderWhitelist.find((x) => x.traderId === traderId);
|
||||||
if (traderWhitelistDetails.rewardCanBeWeapon && this.randomUtil.getChance100(traderWhitelistDetails.weaponRewardChancePercent))
|
if (
|
||||||
|
traderWhitelistDetails.rewardCanBeWeapon
|
||||||
|
&& this.randomUtil.getChance100(traderWhitelistDetails.weaponRewardChancePercent)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// Add a random default preset weapon as reward
|
// Add a random default preset weapon as reward
|
||||||
const defaultPresets = Object.values(this.presetHelper.getDefaultPresets());
|
const defaultPresets = Object.values(this.presetHelper.getDefaultPresets());
|
||||||
const defaultPreset = this.jsonUtil.clone(this.randomUtil.getArrayValue(defaultPresets));
|
const defaultPreset = this.jsonUtil.clone(this.randomUtil.getArrayValue(defaultPresets));
|
||||||
|
|
||||||
// use _encyclopedia as its always the base items _tpl, items[0] isnt guaranteed to be base item
|
// use _encyclopedia as its always the base items _tpl, items[0] isnt guaranteed to be base item
|
||||||
rewards.Success.push(this.generateRewardItem(defaultPreset._encyclopedia, 1, rewardIndex, defaultPreset._items));
|
rewards.Success.push(
|
||||||
|
this.generateRewardItem(defaultPreset._encyclopedia, 1, rewardIndex, defaultPreset._items),
|
||||||
|
);
|
||||||
rewardIndex++;
|
rewardIndex++;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1059,7 +1073,8 @@ export class RepeatableQuestGenerator
|
|||||||
target: traderId,
|
target: traderId,
|
||||||
value: rewardReputation,
|
value: rewardReputation,
|
||||||
type: QuestRewardType.TRADER_STANDING,
|
type: QuestRewardType.TRADER_STANDING,
|
||||||
index: rewardIndex };
|
index: rewardIndex,
|
||||||
|
};
|
||||||
rewards.Success.push(reward);
|
rewards.Success.push(reward);
|
||||||
rewardIndex++;
|
rewardIndex++;
|
||||||
}
|
}
|
||||||
@ -1164,7 +1179,7 @@ export class RepeatableQuestGenerator
|
|||||||
|
|
||||||
if (preset)
|
if (preset)
|
||||||
{
|
{
|
||||||
const rootItem = preset.find(x => x._tpl === tpl);
|
const rootItem = preset.find((x) => x._tpl === tpl);
|
||||||
rewardItem.target = rootItem._id; // Target property and root items id must match
|
rewardItem.target = rootItem._id; // Target property and root items id must match
|
||||||
rewardItem.items = this.itemHelper.reparentItemAndChildren(rootItem, preset);
|
rewardItem.items = this.itemHelper.reparentItemAndChildren(rootItem, preset);
|
||||||
}
|
}
|
||||||
|
@ -108,7 +108,7 @@ export class ScavCaseRewardGenerator
|
|||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (item._props.QuestItem)
|
if (item._props.QuestItem)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
@ -289,13 +289,7 @@ export class ScavCaseRewardGenerator
|
|||||||
const result: Item[][] = [];
|
const result: Item[][] = [];
|
||||||
for (const rewardItemDb of rewardItems)
|
for (const rewardItemDb of rewardItems)
|
||||||
{
|
{
|
||||||
let resultItem: Item[] = [
|
let resultItem: Item[] = [{ _id: this.hashUtil.generate(), _tpl: rewardItemDb._id, upd: undefined }];
|
||||||
{
|
|
||||||
_id: this.hashUtil.generate(),
|
|
||||||
_tpl: rewardItemDb._id,
|
|
||||||
upd: undefined
|
|
||||||
}
|
|
||||||
];
|
|
||||||
const rootItem = resultItem[0];
|
const rootItem = resultItem[0];
|
||||||
|
|
||||||
if (this.itemHelper.isOfBaseclass(rewardItemDb._id, BaseClasses.AMMO_BOX))
|
if (this.itemHelper.isOfBaseclass(rewardItemDb._id, BaseClasses.AMMO_BOX))
|
||||||
@ -303,8 +297,10 @@ export class ScavCaseRewardGenerator
|
|||||||
this.itemHelper.addCartridgesToAmmoBox(resultItem, rewardItemDb);
|
this.itemHelper.addCartridgesToAmmoBox(resultItem, rewardItemDb);
|
||||||
}
|
}
|
||||||
// Armor or weapon = use default preset from globals.json
|
// Armor or weapon = use default preset from globals.json
|
||||||
else if (this.itemHelper.armorItemCanHoldMods(rewardItemDb._id)
|
else if (
|
||||||
|| this.itemHelper.isOfBaseclass(rewardItemDb._id, BaseClasses.WEAPON))
|
this.itemHelper.armorItemCanHoldMods(rewardItemDb._id)
|
||||||
|
|| this.itemHelper.isOfBaseclass(rewardItemDb._id, BaseClasses.WEAPON)
|
||||||
|
)
|
||||||
{
|
{
|
||||||
const preset = this.presetHelper.getDefaultPreset(rewardItemDb._id);
|
const preset = this.presetHelper.getDefaultPreset(rewardItemDb._id);
|
||||||
if (!preset)
|
if (!preset)
|
||||||
@ -313,12 +309,9 @@ export class ScavCaseRewardGenerator
|
|||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
|
// Ensure preset has unique ids and is cloned so we don't alter the preset data stored in memory
|
||||||
const presetAndMods: Item[] = this.itemHelper.replaceIDs(
|
const presetAndMods: Item[] = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(preset._items));
|
||||||
null,
|
|
||||||
this.jsonUtil.clone(preset._items),
|
|
||||||
);
|
|
||||||
this.itemHelper.remapRootItemId(presetAndMods);
|
this.itemHelper.remapRootItemId(presetAndMods);
|
||||||
|
|
||||||
resultItem = presetAndMods;
|
resultItem = presetAndMods;
|
||||||
@ -334,7 +327,7 @@ export class ScavCaseRewardGenerator
|
|||||||
delete rootItem.upd;
|
delete rootItem.upd;
|
||||||
}
|
}
|
||||||
|
|
||||||
result.push(resultItem)
|
result.push(resultItem);
|
||||||
}
|
}
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
|
@ -19,7 +19,7 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
|||||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
@inject("BotWeaponGeneratorHelper") protected botWeaponGeneratorHelper: BotWeaponGeneratorHelper,
|
@inject("BotWeaponGeneratorHelper") protected botWeaponGeneratorHelper: BotWeaponGeneratorHelper,
|
||||||
@inject("RandomUtil") protected randomUtil: RandomUtil
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||||
)
|
)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -75,7 +75,9 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
|||||||
// Prevent infinite loop by only allowing 5 attempts at fitting a magazine into inventory
|
// Prevent infinite loop by only allowing 5 attempts at fitting a magazine into inventory
|
||||||
if (fitAttempts > 5)
|
if (fitAttempts > 5)
|
||||||
{
|
{
|
||||||
this.logger.debug(`Failed ${fitAttempts} times to add magazine ${magazineTpl} to bot inventory, stopping`);
|
this.logger.debug(
|
||||||
|
`Failed ${fitAttempts} times to add magazine ${magazineTpl} to bot inventory, stopping`,
|
||||||
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -108,10 +110,15 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
|||||||
// Edge case - some weapons (SKS) have an internal magazine as default, choose random non-internal magazine to add to bot instead
|
// Edge case - some weapons (SKS) have an internal magazine as default, choose random non-internal magazine to add to bot instead
|
||||||
if (magTemplate._props.ReloadMagType === "InternalMagazine")
|
if (magTemplate._props.ReloadMagType === "InternalMagazine")
|
||||||
{
|
{
|
||||||
const result = this.getRandomExternalMagazineForInternalMagazineGun(inventoryMagGen.getWeaponTemplate()._id, attemptedMagBlacklist);
|
const result = this.getRandomExternalMagazineForInternalMagazineGun(
|
||||||
|
inventoryMagGen.getWeaponTemplate()._id,
|
||||||
|
attemptedMagBlacklist,
|
||||||
|
);
|
||||||
if (!result?._id)
|
if (!result?._id)
|
||||||
{
|
{
|
||||||
this.logger.debug(`Unable to add additional magazine into bot inventory for weapon: ${weapon._name}, attempted: ${fitAttempts} times`);
|
this.logger.debug(
|
||||||
|
`Unable to add additional magazine into bot inventory for weapon: ${weapon._name}, attempted: ${fitAttempts} times`,
|
||||||
|
);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
@ -138,24 +145,29 @@ export class ExternalInventoryMagGen implements IInventoryMagGen
|
|||||||
* @param weaponTpl Weapon to get mag for
|
* @param weaponTpl Weapon to get mag for
|
||||||
* @returns tpl of magazine
|
* @returns tpl of magazine
|
||||||
*/
|
*/
|
||||||
protected getRandomExternalMagazineForInternalMagazineGun(weaponTpl: string, magazineBlacklist: string[]): ITemplateItem
|
protected getRandomExternalMagazineForInternalMagazineGun(
|
||||||
|
weaponTpl: string,
|
||||||
|
magazineBlacklist: string[],
|
||||||
|
): ITemplateItem
|
||||||
{
|
{
|
||||||
// The mag Slot data for the weapon
|
// The mag Slot data for the weapon
|
||||||
const magSlot = this.itemHelper.getItem(weaponTpl)[1]._props.Slots.find(x => x._name === "mod_magazine");
|
const magSlot = this.itemHelper.getItem(weaponTpl)[1]._props.Slots.find((x) => x._name === "mod_magazine");
|
||||||
if (!magSlot)
|
if (!magSlot)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// All possible mags that fit into the weapon excluding blacklisted
|
// All possible mags that fit into the weapon excluding blacklisted
|
||||||
const magazinePool = magSlot._props.filters[0].Filter.filter(x => !magazineBlacklist.includes(x)).map((x) => this.itemHelper.getItem(x)[1]);
|
const magazinePool = magSlot._props.filters[0].Filter.filter((x) => !magazineBlacklist.includes(x)).map((x) =>
|
||||||
|
this.itemHelper.getItem(x)[1]
|
||||||
|
);
|
||||||
if (!magazinePool)
|
if (!magazinePool)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Non-internal magazines that fit into the weapon
|
// Non-internal magazines that fit into the weapon
|
||||||
const externalMagazineOnlyPool = magazinePool.filter(x => x._props.ReloadMagType !== "InternalMagazine");
|
const externalMagazineOnlyPool = magazinePool.filter((x) => x._props.ReloadMagType !== "InternalMagazine");
|
||||||
if (!externalMagazineOnlyPool || externalMagazineOnlyPool?.length === 0)
|
if (!externalMagazineOnlyPool || externalMagazineOnlyPool?.length === 0)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -296,11 +296,7 @@ export class BotGeneratorHelper
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return { incompatible: true, found: false, reason: `item: ${tplToCheck} does not exist in the database` };
|
||||||
incompatible: true,
|
|
||||||
found: false,
|
|
||||||
reason: `item: ${tplToCheck} does not exist in the database`
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// No props property
|
// No props property
|
||||||
@ -314,11 +310,7 @@ export class BotGeneratorHelper
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return { incompatible: true, found: false, reason: `item: ${tplToCheck} does not have a _props field` };
|
||||||
incompatible: true,
|
|
||||||
found: false,
|
|
||||||
reason: `item: ${tplToCheck} does not have a _props field`
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check if any of the current weapon mod templates have the incoming item defined as incompatible
|
// Check if any of the current weapon mod templates have the incoming item defined as incompatible
|
||||||
@ -346,10 +338,7 @@ export class BotGeneratorHelper
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
return {
|
return { incompatible: false, reason: "" };
|
||||||
incompatible: false,
|
|
||||||
reason: ""
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -385,7 +374,7 @@ export class BotGeneratorHelper
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return { incompatible: true, found: false, reason: `item: ${tplToCheck} does not exist in the database` };
|
return { incompatible: true, found: false, reason: `item: ${tplToCheck} does not exist in the database` };
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!itemToEquip._props)
|
if (!itemToEquip._props)
|
||||||
@ -398,11 +387,7 @@ export class BotGeneratorHelper
|
|||||||
}),
|
}),
|
||||||
);
|
);
|
||||||
|
|
||||||
return {
|
return { incompatible: true, found: false, reason: `item: ${tplToCheck} does not have a _props field` };
|
||||||
incompatible: true,
|
|
||||||
found: false,
|
|
||||||
reason: `item: ${tplToCheck} does not have a _props field`
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does an equipped item have a property that blocks the desired item - check for prop "BlocksX" .e.g BlocksEarpiece / BlocksFaceCover
|
// Does an equipped item have a property that blocks the desired item - check for prop "BlocksX" .e.g BlocksEarpiece / BlocksFaceCover
|
||||||
@ -436,7 +421,7 @@ export class BotGeneratorHelper
|
|||||||
// Does item being checked get blocked/block existing item
|
// Does item being checked get blocked/block existing item
|
||||||
if (itemToEquip._props.BlocksHeadwear)
|
if (itemToEquip._props.BlocksHeadwear)
|
||||||
{
|
{
|
||||||
const existingHeadwear = itemsEquipped.find(x => x.slotId === "Headwear");
|
const existingHeadwear = itemsEquipped.find((x) => x.slotId === "Headwear");
|
||||||
if (existingHeadwear)
|
if (existingHeadwear)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@ -448,11 +433,11 @@ export class BotGeneratorHelper
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Does item being checked get blocked/block existing item
|
// Does item being checked get blocked/block existing item
|
||||||
if (itemToEquip._props.BlocksFaceCover)
|
if (itemToEquip._props.BlocksFaceCover)
|
||||||
{
|
{
|
||||||
const existingFaceCover = itemsEquipped.find(item => item.slotId === "FaceCover");
|
const existingFaceCover = itemsEquipped.find((item) => item.slotId === "FaceCover");
|
||||||
if (existingFaceCover)
|
if (existingFaceCover)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@ -468,7 +453,7 @@ export class BotGeneratorHelper
|
|||||||
// Does item being checked get blocked/block existing item
|
// Does item being checked get blocked/block existing item
|
||||||
if (itemToEquip._props.BlocksEarpiece)
|
if (itemToEquip._props.BlocksEarpiece)
|
||||||
{
|
{
|
||||||
const existingEarpiece = itemsEquipped.find(item => item.slotId === "Earpiece");
|
const existingEarpiece = itemsEquipped.find((item) => item.slotId === "Earpiece");
|
||||||
if (existingEarpiece)
|
if (existingEarpiece)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
@ -484,7 +469,7 @@ export class BotGeneratorHelper
|
|||||||
// Does item being checked get blocked/block existing item
|
// Does item being checked get blocked/block existing item
|
||||||
if (itemToEquip._props.BlocksArmorVest)
|
if (itemToEquip._props.BlocksArmorVest)
|
||||||
{
|
{
|
||||||
const existingArmorVest = itemsEquipped.find(item => item.slotId === "ArmorVest");
|
const existingArmorVest = itemsEquipped.find((item) => item.slotId === "ArmorVest");
|
||||||
if (existingArmorVest)
|
if (existingArmorVest)
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
|
@ -186,12 +186,12 @@ export class BotWeaponGeneratorHelper
|
|||||||
{
|
{
|
||||||
// Bot doesnt have any containers we want to add item to
|
// Bot doesnt have any containers we want to add item to
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Unable to add item: ${
|
`Unable to add item: ${itemWithChildren[0]._tpl} to bot as it lacks the following containers: ${
|
||||||
itemWithChildren[0]._tpl
|
equipmentSlots.join(",")
|
||||||
} to bot as it lacks the following containers: ${equipmentSlots.join(",")}`,
|
}`,
|
||||||
);
|
);
|
||||||
|
|
||||||
return ItemAddedResult.NO_CONTAINERS
|
return ItemAddedResult.NO_CONTAINERS;
|
||||||
}
|
}
|
||||||
|
|
||||||
// No container of desired type found, skip to next container type
|
// No container of desired type found, skip to next container type
|
||||||
|
@ -105,9 +105,8 @@ export class GiveSptCommand implements ISptCommand
|
|||||||
{
|
{
|
||||||
// Make sure IDs are unique before adding to array - prevent collisions
|
// Make sure IDs are unique before adding to array - prevent collisions
|
||||||
const presetToSend = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(preset._items));
|
const presetToSend = this.itemHelper.replaceIDs(null, this.jsonUtil.clone(preset._items));
|
||||||
itemsToSend.push(... presetToSend);
|
itemsToSend.push(...presetToSend);
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
else if (this.itemHelper.isOfBaseclass(checkedItem[1]._id, BaseClasses.AMMO_BOX))
|
else if (this.itemHelper.isOfBaseclass(checkedItem[1]._id, BaseClasses.AMMO_BOX))
|
||||||
{
|
{
|
||||||
@ -124,10 +123,7 @@ export class GiveSptCommand implements ISptCommand
|
|||||||
const item: Item = {
|
const item: Item = {
|
||||||
_id: this.hashUtil.generate(),
|
_id: this.hashUtil.generate(),
|
||||||
_tpl: checkedItem[1]._id,
|
_tpl: checkedItem[1]._id,
|
||||||
upd: {
|
upd: { StackObjectsCount: +quantity, SpawnedInSession: true },
|
||||||
StackObjectsCount: +quantity,
|
|
||||||
SpawnedInSession: true
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
itemsToSend.push(...this.itemHelper.splitStack(item));
|
itemsToSend.push(...this.itemHelper.splitStack(item));
|
||||||
}
|
}
|
||||||
|
@ -22,7 +22,7 @@ export class SptDialogueChatBot implements IDialogueChatBot
|
|||||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||||
@inject("MailSendService") protected mailSendService: MailSendService,
|
@inject("MailSendService") protected mailSendService: MailSendService,
|
||||||
@inject("GiftService") protected giftService: GiftService,
|
@inject("GiftService") protected giftService: GiftService,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.coreConfig = this.configServer.getConfig(ConfigTypes.CORE);
|
this.coreConfig = this.configServer.getConfig(ConfigTypes.CORE);
|
||||||
@ -64,7 +64,7 @@ export class SptDialogueChatBot implements IDialogueChatBot
|
|||||||
"Hey! you got the right code!",
|
"Hey! you got the right code!",
|
||||||
"A secret code, how exciting!",
|
"A secret code, how exciting!",
|
||||||
"You found a gift code!",
|
"You found a gift code!",
|
||||||
])
|
]),
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -75,7 +75,7 @@ export class SptDialogueChatBot implements IDialogueChatBot
|
|||||||
this.mailSendService.sendUserMessageToPlayer(
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
sessionId,
|
sessionId,
|
||||||
sptFriendUser,
|
sptFriendUser,
|
||||||
this.randomUtil.getArrayValue(["Looks like you already used that code", "You already have that!!"])
|
this.randomUtil.getArrayValue(["Looks like you already used that code", "You already have that!!"]),
|
||||||
);
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -91,7 +91,7 @@ export class SptDialogueChatBot implements IDialogueChatBot
|
|||||||
"I love you too buddy :3!",
|
"I love you too buddy :3!",
|
||||||
"uwu",
|
"uwu",
|
||||||
`love you too ${sender?.Info?.Nickname}`,
|
`love you too ${sender?.Info?.Nickname}`,
|
||||||
])
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -100,7 +100,7 @@ export class SptDialogueChatBot implements IDialogueChatBot
|
|||||||
this.mailSendService.sendUserMessageToPlayer(
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
sessionId,
|
sessionId,
|
||||||
sptFriendUser,
|
sptFriendUser,
|
||||||
this.randomUtil.getArrayValue(["Its me!!", "spt? i've heard of that project"])
|
this.randomUtil.getArrayValue(["Its me!!", "spt? i've heard of that project"]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -120,7 +120,7 @@ export class SptDialogueChatBot implements IDialogueChatBot
|
|||||||
"Heyyyyy",
|
"Heyyyyy",
|
||||||
"Hey there",
|
"Hey there",
|
||||||
`Hello ${sender?.Info?.Nickname}`,
|
`Hello ${sender?.Info?.Nickname}`,
|
||||||
])
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -134,7 +134,7 @@ export class SptDialogueChatBot implements IDialogueChatBot
|
|||||||
"Cool guy, he made EFT!",
|
"Cool guy, he made EFT!",
|
||||||
"Legend",
|
"Legend",
|
||||||
"Remember when he said webel-webel-webel-webel, classic nikita moment",
|
"Remember when he said webel-webel-webel-webel, classic nikita moment",
|
||||||
])
|
]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -143,7 +143,7 @@ export class SptDialogueChatBot implements IDialogueChatBot
|
|||||||
this.mailSendService.sendUserMessageToPlayer(
|
this.mailSendService.sendUserMessageToPlayer(
|
||||||
sessionId,
|
sessionId,
|
||||||
sptFriendUser,
|
sptFriendUser,
|
||||||
this.randomUtil.getArrayValue(["beep boop", "**sad boop**", "probably", "sometimes", "yeah lol"])
|
this.randomUtil.getArrayValue(["beep boop", "**sad boop**", "probably", "sometimes", "yeah lol"]),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -4,10 +4,7 @@ import { ItemHelper } from "@spt-aki/helpers/ItemHelper";
|
|||||||
import { NotificationSendHelper } from "@spt-aki/helpers/NotificationSendHelper";
|
import { NotificationSendHelper } from "@spt-aki/helpers/NotificationSendHelper";
|
||||||
import { NotifierHelper } from "@spt-aki/helpers/NotifierHelper";
|
import { NotifierHelper } from "@spt-aki/helpers/NotifierHelper";
|
||||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||||
import {
|
import { Dialogue, MessagePreview } from "@spt-aki/models/eft/profile/IAkiProfile";
|
||||||
Dialogue,
|
|
||||||
MessagePreview,
|
|
||||||
} from "@spt-aki/models/eft/profile/IAkiProfile";
|
|
||||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
import { DatabaseServer } from "@spt-aki/servers/DatabaseServer";
|
||||||
import { SaveServer } from "@spt-aki/servers/SaveServer";
|
import { SaveServer } from "@spt-aki/servers/SaveServer";
|
||||||
|
@ -37,7 +37,7 @@ export class HandbookHelper
|
|||||||
|
|
||||||
constructor(
|
constructor(
|
||||||
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
@inject("DatabaseServer") protected databaseServer: DatabaseServer,
|
||||||
@inject("JsonUtil") protected jsonUtil: JsonUtil
|
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
||||||
)
|
)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -168,6 +168,6 @@ export class HandbookHelper
|
|||||||
|
|
||||||
public getCategoryById(handbookId: string): Category
|
public getCategoryById(handbookId: string): Category
|
||||||
{
|
{
|
||||||
return this.databaseServer.getTables().templates.handbook.Categories.find(x => x.Id === handbookId);
|
return this.databaseServer.getTables().templates.handbook.Categories.find((x) => x.Id === handbookId);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -420,11 +420,11 @@ export class HideoutHelper
|
|||||||
// 10-10-2021 From wiki, 1 resource last 12 minutes 38 seconds, 1/12.63333/60 = 0.00131
|
// 10-10-2021 From wiki, 1 resource last 12 minutes 38 seconds, 1/12.63333/60 = 0.00131
|
||||||
let fuelDrainRate = this.databaseServer.getTables().hideout.settings.generatorFuelFlowRate
|
let fuelDrainRate = this.databaseServer.getTables().hideout.settings.generatorFuelFlowRate
|
||||||
* this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn);
|
* this.getTimeElapsedSinceLastServerTick(pmcData, isGeneratorOn);
|
||||||
|
|
||||||
const fuelBonus = pmcData.Bonuses.find((bonus) => bonus.type === BonusType.FUEL_CONSUMPTION);
|
const fuelBonus = pmcData.Bonuses.find((bonus) => bonus.type === BonusType.FUEL_CONSUMPTION);
|
||||||
const fuelBonusPercent = 1.0 - (fuelBonus ? Math.abs(fuelBonus.value) : 0) / 100;
|
const fuelBonusPercent = 1.0 - (fuelBonus ? Math.abs(fuelBonus.value) : 0) / 100;
|
||||||
fuelDrainRate *= fuelBonusPercent;
|
fuelDrainRate *= fuelBonusPercent;
|
||||||
|
|
||||||
// Hideout management resource consumption bonus:
|
// Hideout management resource consumption bonus:
|
||||||
const hideoutManagementConsumptionBonus = 1.0 - this.getHideoutManagementConsumptionBonus(pmcData);
|
const hideoutManagementConsumptionBonus = 1.0 - this.getHideoutManagementConsumptionBonus(pmcData);
|
||||||
fuelDrainRate *= hideoutManagementConsumptionBonus;
|
fuelDrainRate *= hideoutManagementConsumptionBonus;
|
||||||
@ -452,13 +452,13 @@ export class HideoutHelper
|
|||||||
// No fuel left, skip
|
// No fuel left, skip
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Undefined fuel, fresh fuel item and needs its max fuel amount looked up
|
// Undefined fuel, fresh fuel item and needs its max fuel amount looked up
|
||||||
if (!fuelRemaining)
|
if (!fuelRemaining)
|
||||||
{
|
{
|
||||||
const fuelItemTemplate = this.itemHelper.getItem(fuelItemInSlot._tpl)[1];
|
const fuelItemTemplate = this.itemHelper.getItem(fuelItemInSlot._tpl)[1];
|
||||||
pointsConsumed = fuelDrainRate;
|
pointsConsumed = fuelDrainRate;
|
||||||
fuelRemaining = fuelItemTemplate._props.MaxResource - fuelDrainRate;
|
fuelRemaining = fuelItemTemplate._props.MaxResource - fuelDrainRate;
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -481,7 +481,9 @@ export class HideoutHelper
|
|||||||
{
|
{
|
||||||
fuelItemInSlot.upd = this.getAreaUpdObject(1, fuelRemaining, pointsConsumed);
|
fuelItemInSlot.upd = this.getAreaUpdObject(1, fuelRemaining, pointsConsumed);
|
||||||
|
|
||||||
this.logger.debug(`$Profile: ${pmcData._id} Generator has: ${fuelRemaining} fuel left in slot ${i + 1}`);
|
this.logger.debug(
|
||||||
|
`$Profile: ${pmcData._id} Generator has: ${fuelRemaining} fuel left in slot ${i + 1}`,
|
||||||
|
);
|
||||||
hasFuelRemaining = true;
|
hasFuelRemaining = true;
|
||||||
|
|
||||||
break; // Break here to avoid updating all the fuel tanks
|
break; // Break here to avoid updating all the fuel tanks
|
||||||
@ -955,7 +957,7 @@ export class HideoutHelper
|
|||||||
pmcData: IPmcData,
|
pmcData: IPmcData,
|
||||||
request: IHideoutTakeProductionRequestData,
|
request: IHideoutTakeProductionRequestData,
|
||||||
sessionId: string,
|
sessionId: string,
|
||||||
output: IItemEventRouterResponse
|
output: IItemEventRouterResponse,
|
||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
// Get how many coins were crafted and ready to pick up
|
// Get how many coins were crafted and ready to pick up
|
||||||
@ -973,15 +975,11 @@ export class HideoutHelper
|
|||||||
const itemsToAdd: Item[][] = [];
|
const itemsToAdd: Item[][] = [];
|
||||||
for (let index = 0; index < craftedCoinCount; index++)
|
for (let index = 0; index < craftedCoinCount; index++)
|
||||||
{
|
{
|
||||||
itemsToAdd.push(
|
itemsToAdd.push([{
|
||||||
[{
|
_id: this.hashUtil.generate(),
|
||||||
_id: this.hashUtil.generate(),
|
_tpl: HideoutHelper.bitcoinTpl,
|
||||||
_tpl: HideoutHelper.bitcoinTpl,
|
upd: { StackObjectsCount: 1 },
|
||||||
upd: {
|
}]);
|
||||||
StackObjectsCount: 1
|
|
||||||
}
|
|
||||||
}]
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Create request for what we want to add to stash
|
// Create request for what we want to add to stash
|
||||||
@ -989,7 +987,7 @@ export class HideoutHelper
|
|||||||
itemsWithModsToAdd: itemsToAdd,
|
itemsWithModsToAdd: itemsToAdd,
|
||||||
foundInRaid: true,
|
foundInRaid: true,
|
||||||
useSortingTable: false,
|
useSortingTable: false,
|
||||||
callback: null
|
callback: null,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add FiR coins to player inventory
|
// Add FiR coins to player inventory
|
||||||
@ -1070,24 +1068,29 @@ export class HideoutHelper
|
|||||||
*/
|
*/
|
||||||
public applyPlaceOfFameDogtagBonus(pmcData: IPmcData): void
|
public applyPlaceOfFameDogtagBonus(pmcData: IPmcData): void
|
||||||
{
|
{
|
||||||
const fameAreaProfile = pmcData.Hideout.Areas.find(area => area.type === HideoutAreas.PLACE_OF_FAME);
|
const fameAreaProfile = pmcData.Hideout.Areas.find((area) => area.type === HideoutAreas.PLACE_OF_FAME);
|
||||||
|
|
||||||
// Get hideout area 16 bonus array
|
// Get hideout area 16 bonus array
|
||||||
const fameAreaDb = this.databaseServer.getTables().hideout.areas.find((area) => area.type === HideoutAreas.PLACE_OF_FAME);
|
const fameAreaDb = this.databaseServer.getTables().hideout.areas.find((area) =>
|
||||||
|
area.type === HideoutAreas.PLACE_OF_FAME
|
||||||
|
);
|
||||||
|
|
||||||
// Get SkillGroupLevelingBoost object
|
// Get SkillGroupLevelingBoost object
|
||||||
const combatBoostBonusDb = fameAreaDb.stages[fameAreaProfile.level].bonuses.find(bonus => bonus.type === "SkillGroupLevelingBoost");
|
const combatBoostBonusDb = fameAreaDb.stages[fameAreaProfile.level].bonuses.find((bonus) =>
|
||||||
|
bonus.type === "SkillGroupLevelingBoost"
|
||||||
|
);
|
||||||
|
|
||||||
// Get SkillGroupLevelingBoost object in profile
|
// Get SkillGroupLevelingBoost object in profile
|
||||||
const combatBonusProfile = pmcData.Bonuses.find(bonus => bonus.id === combatBoostBonusDb.id);
|
const combatBonusProfile = pmcData.Bonuses.find((bonus) => bonus.id === combatBoostBonusDb.id);
|
||||||
|
|
||||||
// Get all slotted dogtag items
|
// Get all slotted dogtag items
|
||||||
const activeDogtags = pmcData.Inventory.items.filter(item => item?.slotId?.startsWith("dogtag"));
|
const activeDogtags = pmcData.Inventory.items.filter((item) => item?.slotId?.startsWith("dogtag"));
|
||||||
|
|
||||||
// Calculate bonus percent (apply hideoutManagement bonus)
|
// Calculate bonus percent (apply hideoutManagement bonus)
|
||||||
const hideoutManagementSkill = this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.HIDEOUT_MANAGEMENT);
|
const hideoutManagementSkill = this.profileHelper.getSkillFromProfile(pmcData, SkillTypes.HIDEOUT_MANAGEMENT);
|
||||||
const hideoutManagementSkillBonusPercent = 1 + (hideoutManagementSkill.Progress / 10000); // 5100 becomes 0.51, add 1 to it, 1.51
|
const hideoutManagementSkillBonusPercent = 1 + (hideoutManagementSkill.Progress / 10000); // 5100 becomes 0.51, add 1 to it, 1.51
|
||||||
const bonus = this.getDogtagCombatSkillBonusPercent(pmcData, activeDogtags) * hideoutManagementSkillBonusPercent;
|
const bonus = this.getDogtagCombatSkillBonusPercent(pmcData, activeDogtags)
|
||||||
|
* hideoutManagementSkillBonusPercent;
|
||||||
|
|
||||||
// Update bonus value to above calcualted value
|
// Update bonus value to above calcualted value
|
||||||
combatBonusProfile.value = Number.parseFloat(bonus.toFixed(2));
|
combatBonusProfile.value = Number.parseFloat(bonus.toFixed(2));
|
||||||
@ -1112,8 +1115,7 @@ export class HideoutHelper
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (Number.parseInt(dogtag.upd.Dogtag?.AccountId) === pmcData.aid
|
if (Number.parseInt(dogtag.upd.Dogtag?.AccountId) === pmcData.aid)
|
||||||
)
|
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -45,7 +45,7 @@ export class InRaidHelper
|
|||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
@inject("ProfileFixerService") protected profileFixerService: ProfileFixerService,
|
@inject("ProfileFixerService") protected profileFixerService: ProfileFixerService,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
@inject("RandomUtil") protected randomUtil: RandomUtil
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
this.lostOnDeathConfig = this.configServer.getConfig(ConfigTypes.LOST_ON_DEATH);
|
this.lostOnDeathConfig = this.configServer.getConfig(ConfigTypes.LOST_ON_DEATH);
|
||||||
@ -68,7 +68,7 @@ export class InRaidHelper
|
|||||||
*/
|
*/
|
||||||
public addUpdToMoneyFromRaid(items: Item[]): void
|
public addUpdToMoneyFromRaid(items: Item[]): void
|
||||||
{
|
{
|
||||||
for (const item of items.filter(x => this.paymentHelper.isMoneyTpl(x._tpl)))
|
for (const item of items.filter((x) => this.paymentHelper.isMoneyTpl(x._tpl)))
|
||||||
{
|
{
|
||||||
if (!item.upd)
|
if (!item.upd)
|
||||||
{
|
{
|
||||||
@ -129,9 +129,9 @@ export class InRaidHelper
|
|||||||
let pmcStandingForKill = botTypes[victim.Side.toLowerCase()]?.experience?.standingForKill;
|
let pmcStandingForKill = botTypes[victim.Side.toLowerCase()]?.experience?.standingForKill;
|
||||||
const pmcKillProbabilityForScavGain = this.inRaidConfig.pmcKillProbabilityForScavGain;
|
const pmcKillProbabilityForScavGain = this.inRaidConfig.pmcKillProbabilityForScavGain;
|
||||||
|
|
||||||
if(this.randomUtil.rollForChanceProbability(pmcKillProbabilityForScavGain))
|
if (this.randomUtil.rollForChanceProbability(pmcKillProbabilityForScavGain))
|
||||||
{
|
{
|
||||||
pmcStandingForKill += this.inRaidConfig.scavExtractGain
|
pmcStandingForKill += this.inRaidConfig.scavExtractGain;
|
||||||
}
|
}
|
||||||
|
|
||||||
return pmcStandingForKill;
|
return pmcStandingForKill;
|
||||||
@ -151,7 +151,7 @@ export class InRaidHelper
|
|||||||
saveProgressRequest: ISaveProgressRequestData,
|
saveProgressRequest: ISaveProgressRequestData,
|
||||||
sessionID: string,
|
sessionID: string,
|
||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
// Remove skill fatigue values
|
// Remove skill fatigue values
|
||||||
this.resetSkillPointsEarnedDuringRaid(saveProgressRequest.profile);
|
this.resetSkillPointsEarnedDuringRaid(saveProgressRequest.profile);
|
||||||
|
|
||||||
@ -214,19 +214,23 @@ export class InRaidHelper
|
|||||||
if (matchingPreRaidCounter.value !== postRaidValue)
|
if (matchingPreRaidCounter.value !== postRaidValue)
|
||||||
{
|
{
|
||||||
this.logger.error(
|
this.logger.error(
|
||||||
`TaskConditionCounters: ${backendCounterKey} value is different post raid, old: ${matchingPreRaidCounter.value} new: ${postRaidValue}`
|
`TaskConditionCounters: ${backendCounterKey} value is different post raid, old: ${matchingPreRaidCounter.value} new: ${postRaidValue}`,
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Update various serverPMC profile values; quests/limb hp/trader standing with values post-raic
|
* Update various serverPMC profile values; quests/limb hp/trader standing with values post-raic
|
||||||
* @param pmcData Server PMC profile
|
* @param pmcData Server PMC profile
|
||||||
* @param saveProgressRequest Post-raid request data
|
* @param saveProgressRequest Post-raid request data
|
||||||
* @param sessionId Session id
|
* @param sessionId Session id
|
||||||
*/
|
*/
|
||||||
public updatePmcProfileDataPostRaid(pmcData: IPmcData, saveProgressRequest: ISaveProgressRequestData, sessionId: string): void
|
public updatePmcProfileDataPostRaid(
|
||||||
|
pmcData: IPmcData,
|
||||||
|
saveProgressRequest: ISaveProgressRequestData,
|
||||||
|
sessionId: string,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
// Process failed quests then copy everything
|
// Process failed quests then copy everything
|
||||||
this.processAlteredQuests(sessionId, pmcData, pmcData.Quests, saveProgressRequest.profile);
|
this.processAlteredQuests(sessionId, pmcData, pmcData.Quests, saveProgressRequest.profile);
|
||||||
@ -250,13 +254,19 @@ export class InRaidHelper
|
|||||||
* @param saveProgressRequest Post-raid request data
|
* @param saveProgressRequest Post-raid request data
|
||||||
* @param sessionId Session id
|
* @param sessionId Session id
|
||||||
*/
|
*/
|
||||||
public updateScavProfileDataPostRaid(scavData: IPmcData, saveProgressRequest: ISaveProgressRequestData, sessionId: string): void
|
public updateScavProfileDataPostRaid(
|
||||||
|
scavData: IPmcData,
|
||||||
|
saveProgressRequest: ISaveProgressRequestData,
|
||||||
|
sessionId: string,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
// Only copy active quests into scav profile // Progress will later to copied over to PMC profile
|
// Only copy active quests into scav profile // Progress will later to copied over to PMC profile
|
||||||
const existingActiveQuestIds = scavData.Quests?.filter(x => x.status !== QuestStatus.AvailableForStart).map(x => x.qid);
|
const existingActiveQuestIds = scavData.Quests?.filter((x) => x.status !== QuestStatus.AvailableForStart).map((
|
||||||
|
x,
|
||||||
|
) => x.qid);
|
||||||
if (existingActiveQuestIds)
|
if (existingActiveQuestIds)
|
||||||
{
|
{
|
||||||
scavData.Quests = saveProgressRequest.profile.Quests.filter(x => existingActiveQuestIds.includes(x.qid));
|
scavData.Quests = saveProgressRequest.profile.Quests.filter((x) => existingActiveQuestIds.includes(x.qid));
|
||||||
}
|
}
|
||||||
|
|
||||||
this.profileFixerService.checkForAndFixScavProfileIssues(scavData);
|
this.profileFixerService.checkForAndFixScavProfileIssues(scavData);
|
||||||
@ -305,7 +315,7 @@ export class InRaidHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Already completed/failed before raid, skip
|
// Already completed/failed before raid, skip
|
||||||
if ([QuestStatus.Fail, QuestStatus.Success].includes(preRaidQuest.status) )
|
if ([QuestStatus.Fail, QuestStatus.Success].includes(preRaidQuest.status))
|
||||||
{
|
{
|
||||||
// Daily quests get their status altered in-raid to "AvailableForStart",
|
// Daily quests get their status altered in-raid to "AvailableForStart",
|
||||||
// Copy pre-raid status to post raid data
|
// Copy pre-raid status to post raid data
|
||||||
@ -323,7 +333,9 @@ export class InRaidHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Quest with time-gate has unlocked
|
// Quest with time-gate has unlocked
|
||||||
if (postRaidQuestStatus === "AvailableAfter" && postRaidQuest.availableAfter <= this.timeUtil.getTimestamp())
|
if (
|
||||||
|
postRaidQuestStatus === "AvailableAfter" && postRaidQuest.availableAfter <= this.timeUtil.getTimestamp()
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// Flag as ready to complete
|
// Flag as ready to complete
|
||||||
postRaidQuest.status = QuestStatus.AvailableForStart;
|
postRaidQuest.status = QuestStatus.AvailableForStart;
|
||||||
@ -351,7 +363,9 @@ export class InRaidHelper
|
|||||||
// Does failed quest have requirement to collect items from raid
|
// Does failed quest have requirement to collect items from raid
|
||||||
const questDbData = this.questHelper.getQuestFromDb(postRaidQuest.qid, pmcData);
|
const questDbData = this.questHelper.getQuestFromDb(postRaidQuest.qid, pmcData);
|
||||||
// AvailableForFinish
|
// AvailableForFinish
|
||||||
const matchingAffFindConditions = questDbData.conditions.AvailableForFinish.filter(condition => condition.conditionType === "FindItem");
|
const matchingAffFindConditions = questDbData.conditions.AvailableForFinish.filter((condition) =>
|
||||||
|
condition.conditionType === "FindItem"
|
||||||
|
);
|
||||||
const itemsToCollect: string[] = [];
|
const itemsToCollect: string[] = [];
|
||||||
if (matchingAffFindConditions)
|
if (matchingAffFindConditions)
|
||||||
{
|
{
|
||||||
@ -364,21 +378,25 @@ export class InRaidHelper
|
|||||||
|
|
||||||
// Remove quest items from profile as quest has failed and may still be alive
|
// Remove quest items from profile as quest has failed and may still be alive
|
||||||
// Required as restarting the quest from main menu does not remove value from CarriedQuestItems array
|
// Required as restarting the quest from main menu does not remove value from CarriedQuestItems array
|
||||||
postRaidProfile.Stats.Eft.CarriedQuestItems = postRaidProfile.Stats.Eft.CarriedQuestItems.filter(carriedQuestItem => !itemsToCollect.includes(carriedQuestItem))
|
postRaidProfile.Stats.Eft.CarriedQuestItems = postRaidProfile.Stats.Eft.CarriedQuestItems.filter((
|
||||||
|
carriedQuestItem,
|
||||||
|
) => !itemsToCollect.includes(carriedQuestItem));
|
||||||
|
|
||||||
// Remove quest item from profile now quest is failed
|
// Remove quest item from profile now quest is failed
|
||||||
// updateProfileBaseStats() has already passed by ref EFT.Stats, all changes applied to postRaid profile also apply to server profile
|
// updateProfileBaseStats() has already passed by ref EFT.Stats, all changes applied to postRaid profile also apply to server profile
|
||||||
for (const itemTpl of itemsToCollect)
|
for (const itemTpl of itemsToCollect)
|
||||||
{
|
{
|
||||||
// Look for sessioncounter and remove it
|
// Look for sessioncounter and remove it
|
||||||
const counterIndex = postRaidProfile.Stats.Eft.SessionCounters.Items.findIndex(x => x.Key.includes(itemTpl) && x.Key.includes("LootItem"));
|
const counterIndex = postRaidProfile.Stats.Eft.SessionCounters.Items.findIndex((x) =>
|
||||||
|
x.Key.includes(itemTpl) && x.Key.includes("LootItem")
|
||||||
|
);
|
||||||
if (counterIndex > -1)
|
if (counterIndex > -1)
|
||||||
{
|
{
|
||||||
postRaidProfile.Stats.Eft.SessionCounters.Items.splice(counterIndex, 1);
|
postRaidProfile.Stats.Eft.SessionCounters.Items.splice(counterIndex, 1);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Look for quest item and remove it
|
// Look for quest item and remove it
|
||||||
const inventoryItemIndex = postRaidProfile.Inventory.items.findIndex(x => x._tpl === itemTpl);
|
const inventoryItemIndex = postRaidProfile.Inventory.items.findIndex((x) => x._tpl === itemTpl);
|
||||||
if (inventoryItemIndex > -1)
|
if (inventoryItemIndex > -1)
|
||||||
{
|
{
|
||||||
postRaidProfile.Inventory.items.splice(inventoryItemIndex, 1);
|
postRaidProfile.Inventory.items.splice(inventoryItemIndex, 1);
|
||||||
@ -399,13 +417,15 @@ export class InRaidHelper
|
|||||||
const dbQuest = this.questHelper.getQuestFromDb(lockedQuest.qid, null);
|
const dbQuest = this.questHelper.getQuestFromDb(lockedQuest.qid, null);
|
||||||
if (!dbQuest)
|
if (!dbQuest)
|
||||||
{
|
{
|
||||||
this.logger.warning(`Unable to adjust locked quest: ${lockedQuest.qid} as it wasnt found in db. It may not become available later on`);
|
this.logger.warning(
|
||||||
|
`Unable to adjust locked quest: ${lockedQuest.qid} as it wasnt found in db. It may not become available later on`,
|
||||||
|
);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find the time requirement in AvailableForStart array (assuming there is one as quest in locked state === its time-gated)
|
// Find the time requirement in AvailableForStart array (assuming there is one as quest in locked state === its time-gated)
|
||||||
const afsRequirement = dbQuest.conditions.AvailableForStart.find(x => x.conditionType === "Quest");
|
const afsRequirement = dbQuest.conditions.AvailableForStart.find((x) => x.conditionType === "Quest");
|
||||||
if (afsRequirement && afsRequirement.availableAfter > 0)
|
if (afsRequirement && afsRequirement.availableAfter > 0)
|
||||||
{
|
{
|
||||||
// Prereq quest has a wait
|
// Prereq quest has a wait
|
||||||
|
@ -75,16 +75,18 @@ export class InventoryHelper
|
|||||||
* @param pmcData Player profile
|
* @param pmcData Player profile
|
||||||
* @param output Client response object
|
* @param output Client response object
|
||||||
*/
|
*/
|
||||||
public addItemsToStash(sessionId: string, request: IAddItemsDirectRequest, pmcData: IPmcData, output: IItemEventRouterResponse): void
|
public addItemsToStash(
|
||||||
|
sessionId: string,
|
||||||
|
request: IAddItemsDirectRequest,
|
||||||
|
pmcData: IPmcData,
|
||||||
|
output: IItemEventRouterResponse,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
// Check all items fit into inventory before adding
|
// Check all items fit into inventory before adding
|
||||||
if (!this.canPlaceItemsInInventory(sessionId, request.itemsWithModsToAdd))
|
if (!this.canPlaceItemsInInventory(sessionId, request.itemsWithModsToAdd))
|
||||||
{
|
{
|
||||||
// No space, exit
|
// No space, exit
|
||||||
this.httpResponse.appendErrorToOutput(
|
this.httpResponse.appendErrorToOutput(output, this.localisationService.getText("inventory-no_stash_space"));
|
||||||
output,
|
|
||||||
this.localisationService.getText("inventory-no_stash_space"),
|
|
||||||
)
|
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -95,7 +97,7 @@ export class InventoryHelper
|
|||||||
itemWithModsToAdd: itemToAdd,
|
itemWithModsToAdd: itemToAdd,
|
||||||
foundInRaid: request.foundInRaid,
|
foundInRaid: request.foundInRaid,
|
||||||
useSortingTable: request.useSortingTable,
|
useSortingTable: request.useSortingTable,
|
||||||
callback: request.callback
|
callback: request.callback,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add to player inventory
|
// Add to player inventory
|
||||||
@ -114,7 +116,12 @@ export class InventoryHelper
|
|||||||
* @param pmcData Player profile
|
* @param pmcData Player profile
|
||||||
* @param output Client response object
|
* @param output Client response object
|
||||||
*/
|
*/
|
||||||
public addItemToStash(sessionId: string, request: IAddItemDirectRequest, pmcData: IPmcData, output: IItemEventRouterResponse): void
|
public addItemToStash(
|
||||||
|
sessionId: string,
|
||||||
|
request: IAddItemDirectRequest,
|
||||||
|
pmcData: IPmcData,
|
||||||
|
output: IItemEventRouterResponse,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
const itemWithModsToAddClone = this.jsonUtil.clone(request.itemWithModsToAdd);
|
const itemWithModsToAddClone = this.jsonUtil.clone(request.itemWithModsToAdd);
|
||||||
|
|
||||||
@ -167,7 +174,11 @@ export class InventoryHelper
|
|||||||
output.profileChanges[sessionId].items.new.push(...itemWithModsToAddClone);
|
output.profileChanges[sessionId].items.new.push(...itemWithModsToAddClone);
|
||||||
pmcData.Inventory.items.push(...itemWithModsToAddClone);
|
pmcData.Inventory.items.push(...itemWithModsToAddClone);
|
||||||
|
|
||||||
this.logger.debug(`Added ${itemWithModsToAddClone[0].upd?.StackObjectsCount ?? 1} item: ${itemWithModsToAddClone[0]._tpl} with: ${itemWithModsToAddClone.length - 1} mods to inventory`);
|
this.logger.debug(
|
||||||
|
`Added ${itemWithModsToAddClone[0].upd?.StackObjectsCount ?? 1} item: ${
|
||||||
|
itemWithModsToAddClone[0]._tpl
|
||||||
|
} with: ${itemWithModsToAddClone.length - 1} mods to inventory`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -189,7 +200,6 @@ export class InventoryHelper
|
|||||||
{
|
{
|
||||||
item.upd.SpawnedInSession = foundInRaid;
|
item.upd.SpawnedInSession = foundInRaid;
|
||||||
}
|
}
|
||||||
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
if (delete item.upd.SpawnedInSession)
|
if (delete item.upd.SpawnedInSession)
|
||||||
@ -222,10 +232,7 @@ export class InventoryHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public canPlaceItemsInInventory(
|
public canPlaceItemsInInventory(sessionId: string, itemsWithChildren: Item[][]): boolean
|
||||||
sessionId: string,
|
|
||||||
itemsWithChildren: Item[][]
|
|
||||||
): boolean
|
|
||||||
{
|
{
|
||||||
const pmcData = this.profileHelper.getPmcProfile(sessionId);
|
const pmcData = this.profileHelper.getPmcProfile(sessionId);
|
||||||
|
|
||||||
@ -241,10 +248,7 @@ export class InventoryHelper
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
public canPlaceItemInInventory(
|
public canPlaceItemInInventory(stashFS2D: number[][], itemWithChildren: Item[]): boolean
|
||||||
stashFS2D: number[][],
|
|
||||||
itemWithChildren: Item[]
|
|
||||||
): boolean
|
|
||||||
{
|
{
|
||||||
// Get x/y size of item
|
// Get x/y size of item
|
||||||
const rootItem = itemWithChildren[0];
|
const rootItem = itemWithChildren[0];
|
||||||
@ -288,7 +292,8 @@ export class InventoryHelper
|
|||||||
itemWithChildren: Item[],
|
itemWithChildren: Item[],
|
||||||
playerInventory: Inventory,
|
playerInventory: Inventory,
|
||||||
useSortingTable: boolean,
|
useSortingTable: boolean,
|
||||||
output: IItemEventRouterResponse): void
|
output: IItemEventRouterResponse,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
// Get x/y size of item
|
// Get x/y size of item
|
||||||
const rootItem = itemWithChildren[0];
|
const rootItem = itemWithChildren[0];
|
||||||
@ -317,9 +322,7 @@ export class InventoryHelper
|
|||||||
}
|
}
|
||||||
catch (err)
|
catch (err)
|
||||||
{
|
{
|
||||||
const errorText = (typeof err === "string")
|
const errorText = (typeof err === "string") ? ` -> ${err}` : "";
|
||||||
? ` -> ${err}`
|
|
||||||
: "";
|
|
||||||
this.logger.error(this.localisationService.getText("inventory-fill_container_failed", errorText));
|
this.logger.error(this.localisationService.getText("inventory-fill_container_failed", errorText));
|
||||||
|
|
||||||
this.httpResponse.appendErrorToOutput(
|
this.httpResponse.appendErrorToOutput(
|
||||||
@ -388,12 +391,9 @@ export class InventoryHelper
|
|||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
this.httpResponse.appendErrorToOutput(
|
this.httpResponse.appendErrorToOutput(output, this.localisationService.getText("inventory-no_stash_space"));
|
||||||
output,
|
|
||||||
this.localisationService.getText("inventory-no_stash_space"),
|
|
||||||
);
|
|
||||||
|
|
||||||
return
|
return;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -896,7 +896,7 @@ export class InventoryHelper
|
|||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (childFoldable && rootFolded && childFolded)
|
if (childFoldable && rootFolded && childFolded)
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
|
@ -107,7 +107,7 @@ export class ItemHelper
|
|||||||
*/
|
*/
|
||||||
public armorItemCanHoldMods(itemTpl: string): boolean
|
public armorItemCanHoldMods(itemTpl: string): boolean
|
||||||
{
|
{
|
||||||
return this.isOfBaseclasses(itemTpl, [BaseClasses.HEADWEAR, BaseClasses.VEST, BaseClasses.ARMOR]);
|
return this.isOfBaseclasses(itemTpl, [BaseClasses.HEADWEAR, BaseClasses.VEST, BaseClasses.ARMOR]);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -137,15 +137,24 @@ export class ItemHelper
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check if item has slots that match soft insert name ids
|
// Check if item has slots that match soft insert name ids
|
||||||
const softInsertSlotIds = ["groin", "soft_armor_back", "soft_armor_front", "soft_armor_left", "soft_armor_right", "shoulder_l", "shoulder_r", "collar"];
|
const softInsertSlotIds = [
|
||||||
if (itemDbDetails[1]._props.Slots.find(slot => softInsertSlotIds.includes(slot._name.toLowerCase())))
|
"groin",
|
||||||
|
"soft_armor_back",
|
||||||
|
"soft_armor_front",
|
||||||
|
"soft_armor_left",
|
||||||
|
"soft_armor_right",
|
||||||
|
"shoulder_l",
|
||||||
|
"shoulder_r",
|
||||||
|
"collar",
|
||||||
|
];
|
||||||
|
if (itemDbDetails[1]._props.Slots.find((slot) => softInsertSlotIds.includes(slot._name.toLowerCase())))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Also classified as BUILT_IN_INSERTS
|
// Also classified as BUILT_IN_INSERTS
|
||||||
const helmetInsertSlotIds = ["helmet_top", "helmet_back", "helmet_ears"]
|
const helmetInsertSlotIds = ["helmet_top", "helmet_back", "helmet_ears"];
|
||||||
if (itemDbDetails[1]._props.Slots.find(slot => helmetInsertSlotIds.includes(slot._name.toLowerCase())))
|
if (itemDbDetails[1]._props.Slots.find((slot) => helmetInsertSlotIds.includes(slot._name.toLowerCase())))
|
||||||
{
|
{
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
@ -446,8 +455,7 @@ export class ItemHelper
|
|||||||
|
|
||||||
for (const itemFromAssort of assort)
|
for (const itemFromAssort of assort)
|
||||||
{
|
{
|
||||||
if (itemFromAssort.parentId === itemIdToFind
|
if (itemFromAssort.parentId === itemIdToFind && !list.find((item) => itemFromAssort._id === item._id))
|
||||||
&& !list.find((item) => itemFromAssort._id === item._id))
|
|
||||||
{
|
{
|
||||||
list.push(itemFromAssort);
|
list.push(itemFromAssort);
|
||||||
list = list.concat(this.findAndReturnChildrenByAssort(itemFromAssort._id, assort));
|
list = list.concat(this.findAndReturnChildrenByAssort(itemFromAssort._id, assort));
|
||||||
@ -555,7 +563,7 @@ export class ItemHelper
|
|||||||
/**
|
/**
|
||||||
* Turn items like money into separate stacks that adhere to max stack size
|
* Turn items like money into separate stacks that adhere to max stack size
|
||||||
* @param itemToSplit Item to split into smaller stacks
|
* @param itemToSplit Item to split into smaller stacks
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public splitStackIntoSeparateItems(itemToSplit: Item): Item[][]
|
public splitStackIntoSeparateItems(itemToSplit: Item): Item[][]
|
||||||
{
|
{
|
||||||
@ -604,9 +612,7 @@ export class ItemHelper
|
|||||||
{
|
{
|
||||||
const filterResult = itemsToSearch.filter((item) =>
|
const filterResult = itemsToSearch.filter((item) =>
|
||||||
{
|
{
|
||||||
return by === "tpl"
|
return by === "tpl" ? (item._tpl === barterId) : (item._id === barterId);
|
||||||
? (item._tpl === barterId)
|
|
||||||
: (item._id === barterId);
|
|
||||||
});
|
});
|
||||||
|
|
||||||
matchingItems.push(...filterResult);
|
matchingItems.push(...filterResult);
|
||||||
@ -978,7 +984,15 @@ export class ItemHelper
|
|||||||
const cartridgeCountToAdd = (remainingSpace < maxPerStack) ? remainingSpace : maxPerStack;
|
const cartridgeCountToAdd = (remainingSpace < maxPerStack) ? remainingSpace : maxPerStack;
|
||||||
|
|
||||||
// Add cartridge item into items array
|
// Add cartridge item into items array
|
||||||
ammoBox.push(this.createCartridges(ammoBox[0]._id, cartridgeTpl, cartridgeCountToAdd, location, ammoBox[0].upd?.SpawnedInSession));
|
ammoBox.push(
|
||||||
|
this.createCartridges(
|
||||||
|
ammoBox[0]._id,
|
||||||
|
cartridgeTpl,
|
||||||
|
cartridgeCountToAdd,
|
||||||
|
location,
|
||||||
|
ammoBox[0].upd?.SpawnedInSession,
|
||||||
|
),
|
||||||
|
);
|
||||||
|
|
||||||
currentStoredCartridgeCount += cartridgeCountToAdd;
|
currentStoredCartridgeCount += cartridgeCountToAdd;
|
||||||
location++;
|
location++;
|
||||||
@ -1068,7 +1082,9 @@ export class ItemHelper
|
|||||||
|
|
||||||
if (!magazineCartridgeMaxCount)
|
if (!magazineCartridgeMaxCount)
|
||||||
{
|
{
|
||||||
this.logger.warning(`Magazine: ${magTemplate._id} ${magTemplate._name} lacks a Cartridges array, unable to fill magazine with ammo`);
|
this.logger.warning(
|
||||||
|
`Magazine: ${magTemplate._id} ${magTemplate._name} lacks a Cartridges array, unable to fill magazine with ammo`,
|
||||||
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -1104,10 +1120,11 @@ export class ItemHelper
|
|||||||
magazineWithChildCartridges.push(
|
magazineWithChildCartridges.push(
|
||||||
this.createCartridges(
|
this.createCartridges(
|
||||||
magazineWithChildCartridges[0]._id,
|
magazineWithChildCartridges[0]._id,
|
||||||
cartridgeTpl, cartridgeCountToAdd,
|
cartridgeTpl,
|
||||||
|
cartridgeCountToAdd,
|
||||||
location,
|
location,
|
||||||
magazineWithChildCartridges[0].upd?.SpawnedInSession
|
magazineWithChildCartridges[0].upd?.SpawnedInSession,
|
||||||
)
|
),
|
||||||
);
|
);
|
||||||
|
|
||||||
currentStoredCartridgeCount += cartridgeCountToAdd;
|
currentStoredCartridgeCount += cartridgeCountToAdd;
|
||||||
@ -1170,7 +1187,13 @@ export class ItemHelper
|
|||||||
* @param foundInRaid OPTIONAL - Are cartridges found in raid (SpawnedInSession)
|
* @param foundInRaid OPTIONAL - Are cartridges found in raid (SpawnedInSession)
|
||||||
* @returns Item
|
* @returns Item
|
||||||
*/
|
*/
|
||||||
public createCartridges(parentId: string, ammoTpl: string, stackCount: number, location: number, foundInRaid = false): Item
|
public createCartridges(
|
||||||
|
parentId: string,
|
||||||
|
ammoTpl: string,
|
||||||
|
stackCount: number,
|
||||||
|
location: number,
|
||||||
|
foundInRaid = false,
|
||||||
|
): Item
|
||||||
{
|
{
|
||||||
return {
|
return {
|
||||||
_id: this.objectId.generate(),
|
_id: this.objectId.generate(),
|
||||||
@ -1178,10 +1201,7 @@ export class ItemHelper
|
|||||||
parentId: parentId,
|
parentId: parentId,
|
||||||
slotId: "cartridges",
|
slotId: "cartridges",
|
||||||
location: location,
|
location: location,
|
||||||
upd: {
|
upd: { StackObjectsCount: stackCount, SpawnedInSession: foundInRaid },
|
||||||
StackObjectsCount: stackCount,
|
|
||||||
SpawnedInSession: foundInRaid
|
|
||||||
},
|
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1225,7 +1245,12 @@ export class ItemHelper
|
|||||||
* @param requiredOnly Only add required mods
|
* @param requiredOnly Only add required mods
|
||||||
* @returns Item with children
|
* @returns Item with children
|
||||||
*/
|
*/
|
||||||
public addChildSlotItems(itemToAdd: Item[], itemToAddTemplate: ITemplateItem, modSpawnChanceDict: Record<string, number> = null, requiredOnly = false): Item[]
|
public addChildSlotItems(
|
||||||
|
itemToAdd: Item[],
|
||||||
|
itemToAddTemplate: ITemplateItem,
|
||||||
|
modSpawnChanceDict: Record<string, number> = null,
|
||||||
|
requiredOnly = false,
|
||||||
|
): Item[]
|
||||||
{
|
{
|
||||||
const result = itemToAdd;
|
const result = itemToAdd;
|
||||||
const incompatibleModTpls: Set<string> = new Set();
|
const incompatibleModTpls: Set<string> = new Set();
|
||||||
@ -1251,11 +1276,13 @@ export class ItemHelper
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemPool = slot._props.filters[0].Filter ?? [];
|
const itemPool = slot._props.filters[0].Filter ?? [];
|
||||||
const chosenTpl = this.getCompatibleTplFromArray(itemPool, incompatibleModTpls);
|
const chosenTpl = this.getCompatibleTplFromArray(itemPool, incompatibleModTpls);
|
||||||
if (!chosenTpl)
|
if (!chosenTpl)
|
||||||
{
|
{
|
||||||
this.logger.debug(`Unable to add mod to item: ${itemToAddTemplate._id} ${itemToAddTemplate._name} slot: ${slot._name} as no compatible tpl could be found in pool of ${itemPool.length}, skipping`);
|
this.logger.debug(
|
||||||
|
`Unable to add mod to item: ${itemToAddTemplate._id} ${itemToAddTemplate._name} slot: ${slot._name} as no compatible tpl could be found in pool of ${itemPool.length}, skipping`,
|
||||||
|
);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -1264,7 +1291,7 @@ export class ItemHelper
|
|||||||
_id: this.hashUtil.generate(),
|
_id: this.hashUtil.generate(),
|
||||||
_tpl: chosenTpl,
|
_tpl: chosenTpl,
|
||||||
parentId: result[0]._id,
|
parentId: result[0]._id,
|
||||||
slotId: slot._name
|
slotId: slot._name,
|
||||||
};
|
};
|
||||||
result.push(modItemToAdd);
|
result.push(modItemToAdd);
|
||||||
|
|
||||||
@ -1300,7 +1327,7 @@ export class ItemHelper
|
|||||||
if (incompatibleModTpls.has(tpl))
|
if (incompatibleModTpls.has(tpl))
|
||||||
{
|
{
|
||||||
// Incompatible tpl was chosen, try again
|
// Incompatible tpl was chosen, try again
|
||||||
count++
|
count++;
|
||||||
if (count >= possibleTpls.length)
|
if (count >= possibleTpls.length)
|
||||||
{
|
{
|
||||||
return null;
|
return null;
|
||||||
|
@ -285,8 +285,8 @@ export class QuestHelper
|
|||||||
item.upd.SpawnedInSession = true;
|
item.upd.SpawnedInSession = true;
|
||||||
|
|
||||||
// Separate base item from mods, fix stacks
|
// Separate base item from mods, fix stacks
|
||||||
if (item._id === questReward.target) // Is base reward item
|
if (item._id === questReward.target)
|
||||||
{
|
{ // Is base reward item
|
||||||
if (
|
if (
|
||||||
(item.parentId !== undefined) && (item.parentId === "hideout") // Has parentId of hideout
|
(item.parentId !== undefined) && (item.parentId === "hideout") // Has parentId of hideout
|
||||||
&& (item.upd !== undefined) && (item.upd.StackObjectsCount !== undefined) // Has upd with stackobject count
|
&& (item.upd !== undefined) && (item.upd.StackObjectsCount !== undefined) // Has upd with stackobject count
|
||||||
@ -350,12 +350,14 @@ export class QuestHelper
|
|||||||
questReward.items = this.jsonUtil.clone(defaultPreset._items);
|
questReward.items = this.jsonUtil.clone(defaultPreset._items);
|
||||||
|
|
||||||
// Remap target id to the new presets id
|
// Remap target id to the new presets id
|
||||||
questReward.target = questReward.items.find(item => item._tpl === originalRewardRootItem._tpl)._id;
|
questReward.target = questReward.items.find((item) => item._tpl === originalRewardRootItem._tpl)._id;
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.warning(`Unable to find default preset for armor ${originalRewardRootItem._tpl}, adding mods manually`);
|
this.logger.warning(
|
||||||
|
`Unable to find default preset for armor ${originalRewardRootItem._tpl}, adding mods manually`,
|
||||||
|
);
|
||||||
const itemDbData = this.itemHelper.getItem(originalRewardRootItem._tpl)[1];
|
const itemDbData = this.itemHelper.getItem(originalRewardRootItem._tpl)[1];
|
||||||
|
|
||||||
// Hydrate reward with only 'required' mods - necessary for things like helmets otherwise you end up with nvgs/visors etc
|
// Hydrate reward with only 'required' mods - necessary for things like helmets otherwise you end up with nvgs/visors etc
|
||||||
@ -372,9 +374,7 @@ export class QuestHelper
|
|||||||
{
|
{
|
||||||
// Iterate over all rewards with the desired status, flatten out items that have a type of Item
|
// Iterate over all rewards with the desired status, flatten out items that have a type of Item
|
||||||
const questRewards = quest.rewards[QuestStatus[status]].flatMap((reward: IQuestReward) =>
|
const questRewards = quest.rewards[QuestStatus[status]].flatMap((reward: IQuestReward) =>
|
||||||
reward.type === "Item"
|
reward.type === "Item" ? this.processReward(reward) : []
|
||||||
? this.processReward(reward)
|
|
||||||
: []
|
|
||||||
);
|
);
|
||||||
|
|
||||||
return questRewards;
|
return questRewards;
|
||||||
@ -654,7 +654,9 @@ export class QuestHelper
|
|||||||
public getQuestWithOnlyLevelRequirementStartCondition(quest: IQuest): IQuest
|
public getQuestWithOnlyLevelRequirementStartCondition(quest: IQuest): IQuest
|
||||||
{
|
{
|
||||||
quest = this.jsonUtil.clone(quest);
|
quest = this.jsonUtil.clone(quest);
|
||||||
quest.conditions.AvailableForStart = quest.conditions.AvailableForStart.filter((q) => q.conditionType === "Level");
|
quest.conditions.AvailableForStart = quest.conditions.AvailableForStart.filter((q) =>
|
||||||
|
q.conditionType === "Level"
|
||||||
|
);
|
||||||
|
|
||||||
return quest;
|
return quest;
|
||||||
}
|
}
|
||||||
@ -686,7 +688,7 @@ export class QuestHelper
|
|||||||
// Create a dialog message for completing the quest.
|
// Create a dialog message for completing the quest.
|
||||||
const quest = this.getQuestFromDb(failRequest.qid, pmcData);
|
const quest = this.getQuestFromDb(failRequest.qid, pmcData);
|
||||||
|
|
||||||
const questIsRepeatable = pmcData.RepeatableQuests.some(quest => quest.id === failRequest.qid);
|
const questIsRepeatable = pmcData.RepeatableQuests.some((quest) => quest.id === failRequest.qid);
|
||||||
if (!questIsRepeatable)
|
if (!questIsRepeatable)
|
||||||
{
|
{
|
||||||
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
||||||
@ -1007,9 +1009,7 @@ export class QuestHelper
|
|||||||
const questInDb = allQuests.find((x) => x._id === questId);
|
const questInDb = allQuests.find((x) => x._id === questId);
|
||||||
if (!questInDb)
|
if (!questInDb)
|
||||||
{
|
{
|
||||||
this.logger.debug(
|
this.logger.debug(`Unable to find quest: ${questId} in db, cannot get 'FindItem' condition, skipping`);
|
||||||
`Unable to find quest: ${questId} in db, cannot get 'FindItem' condition, skipping`,
|
|
||||||
);
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -565,7 +565,10 @@ export class RagfairOfferHelper
|
|||||||
|
|
||||||
// Filter out presets when search request has multiple buildItems
|
// Filter out presets when search request has multiple buildItems
|
||||||
// Assuming 1 build item = single item e.g. gun
|
// Assuming 1 build item = single item e.g. gun
|
||||||
if (searchRequest.buildCount && this.presetHelper.hasPreset(offerRootItem._tpl) && Object.keys(searchRequest.buildItems).length > 1)
|
if (
|
||||||
|
searchRequest.buildCount && this.presetHelper.hasPreset(offerRootItem._tpl)
|
||||||
|
&& Object.keys(searchRequest.buildItems).length > 1
|
||||||
|
)
|
||||||
{
|
{
|
||||||
// Don't include preset offer
|
// Don't include preset offer
|
||||||
return false;
|
return false;
|
||||||
@ -610,7 +613,8 @@ export class RagfairOfferHelper
|
|||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (this.isConditionItem(offerRootItem)
|
if (
|
||||||
|
this.isConditionItem(offerRootItem)
|
||||||
&& !this.itemQualityInRange(offerRootItem, searchRequest.conditionFrom, searchRequest.conditionTo)
|
&& !this.itemQualityInRange(offerRootItem, searchRequest.conditionFrom, searchRequest.conditionTo)
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -700,9 +704,10 @@ export class RagfairOfferHelper
|
|||||||
*/
|
*/
|
||||||
protected isConditionItem(item: Item): boolean
|
protected isConditionItem(item: Item): boolean
|
||||||
{
|
{
|
||||||
// thanks typescript, undefined assertion is not returnable since it
|
// thanks typescript, undefined assertion is not returnable since it
|
||||||
// tries to return a multitype object
|
// tries to return a multitype object
|
||||||
return (item.upd.MedKit || item.upd.Repairable || item.upd.Resource || item.upd.FoodDrink || item.upd.Key || item.upd.RepairKit)
|
return (item.upd.MedKit || item.upd.Repairable || item.upd.Resource || item.upd.FoodDrink || item.upd.Key
|
||||||
|
|| item.upd.RepairKit)
|
||||||
? true
|
? true
|
||||||
: false;
|
: false;
|
||||||
}
|
}
|
||||||
|
@ -42,11 +42,11 @@ export class RagfairSellHelper
|
|||||||
|
|
||||||
// Base sell chance modified by items quality
|
// Base sell chance modified by items quality
|
||||||
const baseSellChancePercent = sellConfig.base * qualityMultiplier;
|
const baseSellChancePercent = sellConfig.base * qualityMultiplier;
|
||||||
|
|
||||||
// Modfier gets applied twice to either penalize or incentivize over/under pricing (Probably a cleaner way to do this)
|
// Modfier gets applied twice to either penalize or incentivize over/under pricing (Probably a cleaner way to do this)
|
||||||
const sellModifier = (averageOfferPriceRub / playerListedPriceRub) * sellConfig.sellMultiplier;
|
const sellModifier = (averageOfferPriceRub / playerListedPriceRub) * sellConfig.sellMultiplier;
|
||||||
let sellChance = Math.round((baseSellChancePercent * sellModifier) * sellModifier);
|
let sellChance = Math.round((baseSellChancePercent * sellModifier) * sellModifier);
|
||||||
|
|
||||||
// Adjust sell chance if below config value
|
// Adjust sell chance if below config value
|
||||||
if (sellChance < sellConfig.minSellChancePercent)
|
if (sellChance < sellConfig.minSellChancePercent)
|
||||||
{
|
{
|
||||||
@ -73,7 +73,10 @@ export class RagfairSellHelper
|
|||||||
const startTime = this.timeUtil.getTimestamp();
|
const startTime = this.timeUtil.getTimestamp();
|
||||||
|
|
||||||
// Get a time in future to stop simulating sell chances at
|
// Get a time in future to stop simulating sell chances at
|
||||||
const endTime = startTime + this.timeUtil.getHoursAsSeconds(this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour);
|
const endTime = startTime
|
||||||
|
+ this.timeUtil.getHoursAsSeconds(
|
||||||
|
this.databaseServer.getTables().globals.config.RagFair.offerDurationTimeInHour,
|
||||||
|
);
|
||||||
|
|
||||||
let sellTime = startTime;
|
let sellTime = startTime;
|
||||||
let remainingCount = itemSellCount;
|
let remainingCount = itemSellCount;
|
||||||
@ -106,7 +109,10 @@ export class RagfairSellHelper
|
|||||||
const weighting = (100 - sellChancePercent) / 100;
|
const weighting = (100 - sellChancePercent) / 100;
|
||||||
let maximumTime = weighting * (this.ragfairConfig.sell.time.max * 60);
|
let maximumTime = weighting * (this.ragfairConfig.sell.time.max * 60);
|
||||||
const minimumTime = this.ragfairConfig.sell.time.min * 60;
|
const minimumTime = this.ragfairConfig.sell.time.min * 60;
|
||||||
if (maximumTime < minimumTime) maximumTime = minimumTime + 5;
|
if (maximumTime < minimumTime)
|
||||||
|
{
|
||||||
|
maximumTime = minimumTime + 5;
|
||||||
|
}
|
||||||
// Sell time will be random between min/max
|
// Sell time will be random between min/max
|
||||||
sellTime += Math.floor(Math.random() * (maximumTime - minimumTime) + minimumTime);
|
sellTime += Math.floor(Math.random() * (maximumTime - minimumTime) + minimumTime);
|
||||||
|
|
||||||
|
@ -160,7 +160,9 @@ export class RagfairServerHelper
|
|||||||
MessageType.MESSAGE_WITH_ITEMS,
|
MessageType.MESSAGE_WITH_ITEMS,
|
||||||
RagfairServerHelper.goodsReturnedTemplate,
|
RagfairServerHelper.goodsReturnedTemplate,
|
||||||
returnedItems,
|
returnedItems,
|
||||||
this.timeUtil.getHoursAsSeconds(this.databaseServer.getTables().globals.config.RagFair.yourOfferDidNotSellMaxStorageTimeInHour),
|
this.timeUtil.getHoursAsSeconds(
|
||||||
|
this.databaseServer.getTables().globals.config.RagFair.yourOfferDidNotSellMaxStorageTimeInHour,
|
||||||
|
),
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -278,7 +280,7 @@ export class RagfairServerHelper
|
|||||||
/**
|
/**
|
||||||
* Possible bug, returns all items associated with an items tpl, could be multiple presets from globals.json
|
* Possible bug, returns all items associated with an items tpl, could be multiple presets from globals.json
|
||||||
* @param item Preset item
|
* @param item Preset item
|
||||||
* @returns
|
* @returns
|
||||||
*/
|
*/
|
||||||
public getPresetItemsByTpl(item: Item): Item[]
|
public getPresetItemsByTpl(item: Item): Item[]
|
||||||
{
|
{
|
||||||
|
@ -45,7 +45,8 @@ export class TradeHelper
|
|||||||
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
|
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
|
||||||
@inject("RagfairServer") protected ragfairServer: RagfairServer,
|
@inject("RagfairServer") protected ragfairServer: RagfairServer,
|
||||||
@inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper,
|
@inject("TraderAssortHelper") protected traderAssortHelper: TraderAssortHelper,
|
||||||
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService: TraderPurchasePersisterService,
|
@inject("TraderPurchasePersisterService") protected traderPurchasePersisterService:
|
||||||
|
TraderPurchasePersisterService,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
@ -71,7 +72,7 @@ export class TradeHelper
|
|||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
let offerItems: Item[] = [];
|
let offerItems: Item[] = [];
|
||||||
let buyCallback: { (buyCount: number) };
|
let buyCallback: { (buyCount: number); };
|
||||||
if (buyRequestData.tid.toLocaleLowerCase() === "ragfair")
|
if (buyRequestData.tid.toLocaleLowerCase() === "ragfair")
|
||||||
{
|
{
|
||||||
buyCallback = (buyCount: number) =>
|
buyCallback = (buyCount: number) =>
|
||||||
@ -81,23 +82,26 @@ export class TradeHelper
|
|||||||
// We store ragfair offerid in buyRequestData.item_id
|
// We store ragfair offerid in buyRequestData.item_id
|
||||||
const offerWithItem = allOffers.find((x) => x._id === buyRequestData.item_id);
|
const offerWithItem = allOffers.find((x) => x._id === buyRequestData.item_id);
|
||||||
const itemPurchased = offerWithItem.items[0];
|
const itemPurchased = offerWithItem.items[0];
|
||||||
|
|
||||||
// Ensure purchase does not exceed trader item limit
|
// Ensure purchase does not exceed trader item limit
|
||||||
const assortHasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
|
const assortHasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
|
||||||
if (assortHasBuyRestrictions)
|
if (assortHasBuyRestrictions)
|
||||||
{
|
{
|
||||||
this.checkPurchaseIsWithinTraderItemLimit(sessionID, buyRequestData.tid, itemPurchased, buyRequestData.item_id, buyCount);
|
this.checkPurchaseIsWithinTraderItemLimit(
|
||||||
|
sessionID,
|
||||||
|
buyRequestData.tid,
|
||||||
|
itemPurchased,
|
||||||
|
buyRequestData.item_id,
|
||||||
|
buyCount,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrement trader item count
|
// Decrement trader item count
|
||||||
if (this.traderConfig.persistPurchaseDataInProfile && assortHasBuyRestrictions)
|
if (this.traderConfig.persistPurchaseDataInProfile && assortHasBuyRestrictions)
|
||||||
{
|
{
|
||||||
const itemPurchaseDat = {
|
const itemPurchaseDat = {
|
||||||
items: [{
|
items: [{ itemId: buyRequestData.item_id, count: buyCount }],
|
||||||
itemId: buyRequestData.item_id,
|
traderId: buyRequestData.tid,
|
||||||
count: buyCount
|
|
||||||
}],
|
|
||||||
traderId: buyRequestData.tid
|
|
||||||
};
|
};
|
||||||
this.traderHelper.addTraderPurchasesToPlayerProfile(sessionID, itemPurchaseDat);
|
this.traderHelper.addTraderPurchasesToPlayerProfile(sessionID, itemPurchaseDat);
|
||||||
}
|
}
|
||||||
@ -121,10 +125,10 @@ export class TradeHelper
|
|||||||
// Update assort/flea item values
|
// Update assort/flea item values
|
||||||
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items;
|
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items;
|
||||||
const itemPurchased = traderAssorts.find((assort) => assort._id === buyRequestData.item_id);
|
const itemPurchased = traderAssorts.find((assort) => assort._id === buyRequestData.item_id);
|
||||||
|
|
||||||
// Decrement trader item count
|
// Decrement trader item count
|
||||||
itemPurchased.upd.StackObjectsCount -= buyCount;
|
itemPurchased.upd.StackObjectsCount -= buyCount;
|
||||||
|
|
||||||
this.fenceService.amendOrRemoveFenceOffer(buyRequestData.item_id, buyCount);
|
this.fenceService.amendOrRemoveFenceOffer(buyRequestData.item_id, buyCount);
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -150,12 +154,17 @@ export class TradeHelper
|
|||||||
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items;
|
const traderAssorts = this.traderHelper.getTraderAssortsByTraderId(buyRequestData.tid).items;
|
||||||
const itemPurchased = traderAssorts.find((x) => x._id === buyRequestData.item_id);
|
const itemPurchased = traderAssorts.find((x) => x._id === buyRequestData.item_id);
|
||||||
|
|
||||||
|
|
||||||
// Ensure purchase does not exceed trader item limit
|
// Ensure purchase does not exceed trader item limit
|
||||||
const assortHasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
|
const assortHasBuyRestrictions = this.itemHelper.hasBuyRestrictions(itemPurchased);
|
||||||
if (assortHasBuyRestrictions)
|
if (assortHasBuyRestrictions)
|
||||||
{
|
{
|
||||||
this.checkPurchaseIsWithinTraderItemLimit(sessionID, buyRequestData.tid, itemPurchased, buyRequestData.item_id, buyCount);
|
this.checkPurchaseIsWithinTraderItemLimit(
|
||||||
|
sessionID,
|
||||||
|
buyRequestData.tid,
|
||||||
|
itemPurchased,
|
||||||
|
buyRequestData.item_id,
|
||||||
|
buyCount,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Decrement trader item count
|
// Decrement trader item count
|
||||||
@ -164,11 +173,8 @@ export class TradeHelper
|
|||||||
if (this.traderConfig.persistPurchaseDataInProfile && assortHasBuyRestrictions)
|
if (this.traderConfig.persistPurchaseDataInProfile && assortHasBuyRestrictions)
|
||||||
{
|
{
|
||||||
const itemPurchaseDat = {
|
const itemPurchaseDat = {
|
||||||
items: [{
|
items: [{ itemId: buyRequestData.item_id, count: buyCount }],
|
||||||
itemId: buyRequestData.item_id,
|
traderId: buyRequestData.tid,
|
||||||
count: buyCount
|
|
||||||
}],
|
|
||||||
traderId: buyRequestData.tid
|
|
||||||
};
|
};
|
||||||
this.traderHelper.addTraderPurchasesToPlayerProfile(sessionID, itemPurchaseDat);
|
this.traderHelper.addTraderPurchasesToPlayerProfile(sessionID, itemPurchaseDat);
|
||||||
}
|
}
|
||||||
@ -182,7 +188,7 @@ export class TradeHelper
|
|||||||
|
|
||||||
// Get all trader assort items
|
// Get all trader assort items
|
||||||
const traderItems = this.traderAssortHelper.getAssort(sessionID, buyRequestData.tid).items;
|
const traderItems = this.traderAssortHelper.getAssort(sessionID, buyRequestData.tid).items;
|
||||||
|
|
||||||
// Get item + children for purchase
|
// Get item + children for purchase
|
||||||
const relevantItems = this.itemHelper.findAndReturnChildrenAsItems(traderItems, buyRequestData.item_id);
|
const relevantItems = this.itemHelper.findAndReturnChildrenAsItems(traderItems, buyRequestData.item_id);
|
||||||
offerItems.push(...relevantItems);
|
offerItems.push(...relevantItems);
|
||||||
@ -209,7 +215,7 @@ export class TradeHelper
|
|||||||
itemWithModsToAdd: this.itemHelper.reparentItemAndChildren(offerItems[0], offerItems),
|
itemWithModsToAdd: this.itemHelper.reparentItemAndChildren(offerItems[0], offerItems),
|
||||||
foundInRaid: foundInRaid,
|
foundInRaid: foundInRaid,
|
||||||
callback: buyCallback,
|
callback: buyCallback,
|
||||||
useSortingTable: false
|
useSortingTable: false,
|
||||||
};
|
};
|
||||||
|
|
||||||
// Add item + children to stash
|
// Add item + children to stash
|
||||||
@ -299,9 +305,19 @@ export class TradeHelper
|
|||||||
* @param assortId Id of assort being purchased
|
* @param assortId Id of assort being purchased
|
||||||
* @param count How many of the item are being bought
|
* @param count How many of the item are being bought
|
||||||
*/
|
*/
|
||||||
protected checkPurchaseIsWithinTraderItemLimit(sessionId: string, traderId: string, assortBeingPurchased: Item, assortId: string, count: number): void
|
protected checkPurchaseIsWithinTraderItemLimit(
|
||||||
|
sessionId: string,
|
||||||
|
traderId: string,
|
||||||
|
assortBeingPurchased: Item,
|
||||||
|
assortId: string,
|
||||||
|
count: number,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
const traderPurchaseData = this.traderPurchasePersisterService.getProfileTraderPurchase(sessionId, traderId, assortBeingPurchased._id);
|
const traderPurchaseData = this.traderPurchasePersisterService.getProfileTraderPurchase(
|
||||||
|
sessionId,
|
||||||
|
traderId,
|
||||||
|
assortBeingPurchased._id,
|
||||||
|
);
|
||||||
if ((traderPurchaseData?.count ?? 0 + count) > assortBeingPurchased.upd?.BuyRestrictionMax)
|
if ((traderPurchaseData?.count ?? 0 + count) > assortBeingPurchased.upd?.BuyRestrictionMax)
|
||||||
{
|
{
|
||||||
throw new Error(
|
throw new Error(
|
||||||
|
@ -148,7 +148,7 @@ export class TraderAssortHelper
|
|||||||
protected resetBuyRestrictionCurrentValue(assortItems: Item[]): void
|
protected resetBuyRestrictionCurrentValue(assortItems: Item[]): void
|
||||||
{
|
{
|
||||||
// iterate over root items
|
// iterate over root items
|
||||||
for (const assort of assortItems.filter(item => item.slotId === "hideout"))
|
for (const assort of assortItems.filter((item) => item.slotId === "hideout"))
|
||||||
{
|
{
|
||||||
// no value to adjust
|
// no value to adjust
|
||||||
if (!assort.upd.BuyRestrictionCurrent)
|
if (!assort.upd.BuyRestrictionCurrent)
|
||||||
|
@ -146,10 +146,12 @@ export class PreAkiModLoader implements IModLoader
|
|||||||
const modOrder = this.vfs.readFile(this.modOrderPath, { encoding: "utf8" });
|
const modOrder = this.vfs.readFile(this.modOrderPath, { encoding: "utf8" });
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
this.jsonUtil.deserialize<any>(modOrder, this.modOrderPath).order.forEach((mod: string, index: number) =>
|
this.jsonUtil.deserialize<any>(modOrder, this.modOrderPath).order.forEach(
|
||||||
{
|
(mod: string, index: number) =>
|
||||||
this.order[mod] = index;
|
{
|
||||||
});
|
this.order[mod] = index;
|
||||||
|
},
|
||||||
|
);
|
||||||
}
|
}
|
||||||
catch (error)
|
catch (error)
|
||||||
{
|
{
|
||||||
@ -429,7 +431,7 @@ export class PreAkiModLoader implements IModLoader
|
|||||||
public sortModsLoadOrder(): string[]
|
public sortModsLoadOrder(): string[]
|
||||||
{
|
{
|
||||||
// if loadorder.json exists: load it, otherwise generate load order
|
// if loadorder.json exists: load it, otherwise generate load order
|
||||||
const loadOrderPath = `${this.basepath}loadorder.json`
|
const loadOrderPath = `${this.basepath}loadorder.json`;
|
||||||
if (this.vfs.exists(loadOrderPath))
|
if (this.vfs.exists(loadOrderPath))
|
||||||
{
|
{
|
||||||
return this.jsonUtil.deserialize(this.vfs.readFile(loadOrderPath), loadOrderPath);
|
return this.jsonUtil.deserialize(this.vfs.readFile(loadOrderPath), loadOrderPath);
|
||||||
|
@ -1,11 +1,11 @@
|
|||||||
import { IMagazineTemplateAmmoItem } from "../profile/IAkiProfile"
|
import { IMagazineTemplateAmmoItem } from "../profile/IAkiProfile";
|
||||||
|
|
||||||
export interface ISetMagazineRequest
|
export interface ISetMagazineRequest
|
||||||
{
|
{
|
||||||
Id: string
|
Id: string;
|
||||||
Name: string
|
Name: string;
|
||||||
Caliber: string
|
Caliber: string;
|
||||||
Items: IMagazineTemplateAmmoItem[]
|
Items: IMagazineTemplateAmmoItem[];
|
||||||
TopCount: number
|
TopCount: number;
|
||||||
BottomCount: number
|
BottomCount: number;
|
||||||
}
|
}
|
||||||
|
@ -77,9 +77,9 @@ export interface IConfig
|
|||||||
SkillFatigueReset: number;
|
SkillFatigueReset: number;
|
||||||
DiscardLimitsEnabled: boolean;
|
DiscardLimitsEnabled: boolean;
|
||||||
EventSettings: IEventSettings;
|
EventSettings: IEventSettings;
|
||||||
FavoriteItemsSettings: IFavoriteItemsSettings
|
FavoriteItemsSettings: IFavoriteItemsSettings;
|
||||||
VaultingSettings: IVaultingSettings
|
VaultingSettings: IVaultingSettings;
|
||||||
BTRSettings: IBTRSettings
|
BTRSettings: IBTRSettings;
|
||||||
EventType: string[];
|
EventType: string[];
|
||||||
WalkSpeed: Ixyz;
|
WalkSpeed: Ixyz;
|
||||||
SprintSpeed: Ixyz;
|
SprintSpeed: Ixyz;
|
||||||
@ -1036,99 +1036,98 @@ export interface IRestrictionsInRaid
|
|||||||
|
|
||||||
export interface IFavoriteItemsSettings
|
export interface IFavoriteItemsSettings
|
||||||
{
|
{
|
||||||
WeaponStandMaxItemsCount: number
|
WeaponStandMaxItemsCount: number;
|
||||||
PlaceOfFameMaxItemsCount: number
|
PlaceOfFameMaxItemsCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVaultingSettings
|
export interface IVaultingSettings
|
||||||
{
|
{
|
||||||
IsActive: boolean
|
IsActive: boolean;
|
||||||
VaultingInputTime: number
|
VaultingInputTime: number;
|
||||||
GridSettings: IVaultingGridSettings
|
GridSettings: IVaultingGridSettings;
|
||||||
MovesSettings: IVaultingMovesSettings
|
MovesSettings: IVaultingMovesSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVaultingGridSettings
|
export interface IVaultingGridSettings
|
||||||
{
|
{
|
||||||
GridSizeX: number
|
GridSizeX: number;
|
||||||
GridSizeY: number
|
GridSizeY: number;
|
||||||
GridSizeZ: number
|
GridSizeZ: number;
|
||||||
SteppingLengthX: number
|
SteppingLengthX: number;
|
||||||
SteppingLengthY: number
|
SteppingLengthY: number;
|
||||||
SteppingLengthZ: number
|
SteppingLengthZ: number;
|
||||||
GridOffsetX: number
|
GridOffsetX: number;
|
||||||
GridOffsetY: number
|
GridOffsetY: number;
|
||||||
GridOffsetZ: number
|
GridOffsetZ: number;
|
||||||
OffsetFactor: number
|
OffsetFactor: number;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVaultingMovesSettings
|
export interface IVaultingMovesSettings
|
||||||
{
|
{
|
||||||
VaultSettings: IVaultingSubMoveSettings
|
VaultSettings: IVaultingSubMoveSettings;
|
||||||
ClimbSettings: IVaultingSubMoveSettings
|
ClimbSettings: IVaultingSubMoveSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IVaultingSubMoveSettings
|
export interface IVaultingSubMoveSettings
|
||||||
{
|
{
|
||||||
IsActive: boolean
|
IsActive: boolean;
|
||||||
MaxWithoutHandHeight: number
|
MaxWithoutHandHeight: number;
|
||||||
SpeedRange: Ixyz
|
SpeedRange: Ixyz;
|
||||||
MoveRestrictions: IMoveRestrictions
|
MoveRestrictions: IMoveRestrictions;
|
||||||
AutoMoveRestrictions: IMoveRestrictions
|
AutoMoveRestrictions: IMoveRestrictions;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMoveRestrictions
|
export interface IMoveRestrictions
|
||||||
{
|
{
|
||||||
IsActive: boolean
|
IsActive: boolean;
|
||||||
MinDistantToInteract: number
|
MinDistantToInteract: number;
|
||||||
MinHeight: number
|
MinHeight: number;
|
||||||
MaxHeight: number
|
MaxHeight: number;
|
||||||
MinLength: number
|
MinLength: number;
|
||||||
MaxLength: number
|
MaxLength: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBTRSettings
|
export interface IBTRSettings
|
||||||
{
|
{
|
||||||
LocationsWithBTR: string[]
|
LocationsWithBTR: string[];
|
||||||
BasePriceTaxi: number
|
BasePriceTaxi: number;
|
||||||
AddPriceTaxi: number
|
AddPriceTaxi: number;
|
||||||
CleanUpPrice: number
|
CleanUpPrice: number;
|
||||||
DeliveryPrice: number
|
DeliveryPrice: number;
|
||||||
ModDeliveryCost: number
|
ModDeliveryCost: number;
|
||||||
BearPriceMod: number
|
BearPriceMod: number;
|
||||||
UsecPriceMod: number
|
UsecPriceMod: number;
|
||||||
ScavPriceMod: number
|
ScavPriceMod: number;
|
||||||
CoefficientDiscountCharisma: number
|
CoefficientDiscountCharisma: number;
|
||||||
DeliveryMinPrice: number
|
DeliveryMinPrice: number;
|
||||||
TaxiMinPrice: number
|
TaxiMinPrice: number;
|
||||||
BotCoverMinPrice: number
|
BotCoverMinPrice: number;
|
||||||
MapsConfigs: Record<string, IBtrMapConfig>
|
MapsConfigs: Record<string, IBtrMapConfig>;
|
||||||
DiameterWheel: number
|
DiameterWheel: number;
|
||||||
HeightWheel: number
|
HeightWheel: number;
|
||||||
HeightWheelMaxPosLimit: number
|
HeightWheelMaxPosLimit: number;
|
||||||
HeightWheelMinPosLimit: number
|
HeightWheelMinPosLimit: number;
|
||||||
SnapToSurfaceWheelsSpeed: number
|
SnapToSurfaceWheelsSpeed: number;
|
||||||
CheckSurfaceForWheelsTimer: number
|
CheckSurfaceForWheelsTimer: number;
|
||||||
HeightWheelOffset: number
|
HeightWheelOffset: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBtrMapConfig
|
export interface IBtrMapConfig
|
||||||
{
|
{
|
||||||
mapID: string
|
mapID: string;
|
||||||
pathsConfigurations: IBtrMapConfig[]
|
pathsConfigurations: IBtrMapConfig[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBtrMapConfig
|
export interface IBtrMapConfig
|
||||||
{
|
{
|
||||||
id: string
|
id: string;
|
||||||
enterPoint: string
|
enterPoint: string;
|
||||||
exitPoint: string
|
exitPoint: string;
|
||||||
pathPoints: string[]
|
pathPoints: string[];
|
||||||
once: boolean
|
once: boolean;
|
||||||
circle: boolean
|
circle: boolean;
|
||||||
circleCount: number
|
circleCount: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISquadSettings
|
export interface ISquadSettings
|
||||||
{
|
{
|
||||||
@ -1643,11 +1642,11 @@ export interface IFenceLevel
|
|||||||
BotHelpChance: number;
|
BotHelpChance: number;
|
||||||
BotSpreadoutChance: number;
|
BotSpreadoutChance: number;
|
||||||
BotStopChance: number;
|
BotStopChance: number;
|
||||||
PriceModTaxi: number
|
PriceModTaxi: number;
|
||||||
PriceModDelivery: number
|
PriceModDelivery: number;
|
||||||
PriceModCleanUp: number
|
PriceModCleanUp: number;
|
||||||
DeliveryGridSize: Ixyz
|
DeliveryGridSize: Ixyz;
|
||||||
CanInteractWithBtr: boolean
|
CanInteractWithBtr: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IInertia
|
export interface IInertia
|
||||||
@ -1766,14 +1765,15 @@ export interface IAudioGroupPreset
|
|||||||
|
|
||||||
export interface IEnvironmentSettings
|
export interface IEnvironmentSettings
|
||||||
{
|
{
|
||||||
SnowStepsVolumeMultiplier: number
|
SnowStepsVolumeMultiplier: number;
|
||||||
SurfaceMultipliers: ISurfaceMultiplier[]
|
SurfaceMultipliers: ISurfaceMultiplier[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISurfaceMultiplier {
|
export interface ISurfaceMultiplier
|
||||||
SurfaceType: string
|
{
|
||||||
VolumeMult: number
|
SurfaceType: string;
|
||||||
}
|
VolumeMult: number;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IBotWeaponScattering
|
export interface IBotWeaponScattering
|
||||||
{
|
{
|
||||||
|
@ -229,7 +229,7 @@ export interface Exit
|
|||||||
Chance: number;
|
Chance: number;
|
||||||
Count: number;
|
Count: number;
|
||||||
EntryPoints: string;
|
EntryPoints: string;
|
||||||
EventAvailable: boolean
|
EventAvailable: boolean;
|
||||||
ExfiltrationTime: number;
|
ExfiltrationTime: number;
|
||||||
ExfiltrationType: string;
|
ExfiltrationType: string;
|
||||||
RequiredSlot?: string;
|
RequiredSlot?: string;
|
||||||
|
@ -5,12 +5,12 @@ export interface IPmcData extends IBotBase
|
|||||||
|
|
||||||
export interface IPostRaidPmcData extends IBotBase
|
export interface IPostRaidPmcData extends IBotBase
|
||||||
{
|
{
|
||||||
Stats: IPostRaidStats
|
Stats: IPostRaidStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPostRaidStats
|
export interface IPostRaidStats
|
||||||
{
|
{
|
||||||
Eft: IEftStats
|
Eft: IEftStats;
|
||||||
/** Only found in profile we get from client post raid */
|
/** Only found in profile we get from client post raid */
|
||||||
Arena: IEftStats
|
Arena: IEftStats;
|
||||||
}
|
}
|
||||||
|
@ -1,20 +1,20 @@
|
|||||||
import { IQuestConditionTypes, IQuestRewards } from "./IQuest"
|
import { IQuestConditionTypes, IQuestRewards } from "./IQuest";
|
||||||
|
|
||||||
export interface IAchievement
|
export interface IAchievement
|
||||||
{
|
{
|
||||||
id: string
|
id: string;
|
||||||
imageUrl: string
|
imageUrl: string;
|
||||||
assetPath: string
|
assetPath: string;
|
||||||
rewards: IQuestRewards
|
rewards: IQuestRewards;
|
||||||
conditions: IQuestConditionTypes
|
conditions: IQuestConditionTypes;
|
||||||
instantComplete: boolean
|
instantComplete: boolean;
|
||||||
showNotificationsInGame: boolean
|
showNotificationsInGame: boolean;
|
||||||
showProgress: boolean
|
showProgress: boolean;
|
||||||
prefab: string
|
prefab: string;
|
||||||
rarity: string
|
rarity: string;
|
||||||
hidden: boolean
|
hidden: boolean;
|
||||||
showConditions: boolean
|
showConditions: boolean;
|
||||||
progressBarEnabled: boolean
|
progressBarEnabled: boolean;
|
||||||
side: string
|
side: string;
|
||||||
index: number
|
index: number;
|
||||||
}
|
}
|
||||||
|
@ -29,7 +29,7 @@ export interface IBotBase
|
|||||||
UnlockedInfo: IUnlockedInfo;
|
UnlockedInfo: IUnlockedInfo;
|
||||||
RagfairInfo: RagfairInfo;
|
RagfairInfo: RagfairInfo;
|
||||||
/** Achievement id and timestamp */
|
/** Achievement id and timestamp */
|
||||||
Achievements: Record<string, number>
|
Achievements: Record<string, number>;
|
||||||
RepeatableQuests: IPmcDataRepeatableQuest[];
|
RepeatableQuests: IPmcDataRepeatableQuest[];
|
||||||
Bonuses: Bonus[];
|
Bonuses: Bonus[];
|
||||||
Notes: Notes;
|
Notes: Notes;
|
||||||
@ -43,11 +43,11 @@ export interface IBotBase
|
|||||||
|
|
||||||
export interface ITaskConditionCounter
|
export interface ITaskConditionCounter
|
||||||
{
|
{
|
||||||
id: string
|
id: string;
|
||||||
type: string
|
type: string;
|
||||||
value: number
|
value: number;
|
||||||
/** Quest id */
|
/** Quest id */
|
||||||
sourceId: string
|
sourceId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUnlockedInfo
|
export interface IUnlockedInfo
|
||||||
@ -165,7 +165,7 @@ export interface Inventory
|
|||||||
/** Key is hideout area enum numeric as string e.g. "24", value is area _id */
|
/** Key is hideout area enum numeric as string e.g. "24", value is area _id */
|
||||||
hideoutAreaStashes: Record<string, string>;
|
hideoutAreaStashes: Record<string, string>;
|
||||||
fastPanel: Record<string, string>;
|
fastPanel: Record<string, string>;
|
||||||
favoriteItems: string[]
|
favoriteItems: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBaseJsonSkills
|
export interface IBaseJsonSkills
|
||||||
@ -510,4 +510,4 @@ export interface Note
|
|||||||
{
|
{
|
||||||
Time: number;
|
Time: number;
|
||||||
Text: string;
|
Text: string;
|
||||||
}
|
}
|
||||||
|
@ -54,10 +54,10 @@ export interface IQuestCondition
|
|||||||
{
|
{
|
||||||
id: string;
|
id: string;
|
||||||
index?: number;
|
index?: number;
|
||||||
compareMethod?: string
|
compareMethod?: string;
|
||||||
dynamicLocale: boolean;
|
dynamicLocale: boolean;
|
||||||
visibilityConditions?: VisibilityCondition[];
|
visibilityConditions?: VisibilityCondition[];
|
||||||
globalQuestCounterId?: string
|
globalQuestCounterId?: string;
|
||||||
parentId?: string;
|
parentId?: string;
|
||||||
target: string[] | string;
|
target: string[] | string;
|
||||||
value?: string | number;
|
value?: string | number;
|
||||||
@ -75,7 +75,7 @@ export interface IQuestCondition
|
|||||||
plantTime?: number;
|
plantTime?: number;
|
||||||
zoneId?: string;
|
zoneId?: string;
|
||||||
countInRaid?: boolean;
|
countInRaid?: boolean;
|
||||||
completeInSeconds?: number
|
completeInSeconds?: number;
|
||||||
isEncoded?: boolean;
|
isEncoded?: boolean;
|
||||||
conditionType?: string;
|
conditionType?: string;
|
||||||
}
|
}
|
||||||
@ -89,48 +89,48 @@ export interface IQuestConditionCounter
|
|||||||
export interface IQuestConditionCounterCondition
|
export interface IQuestConditionCounterCondition
|
||||||
{
|
{
|
||||||
id: string;
|
id: string;
|
||||||
dynamicLocale: boolean
|
dynamicLocale: boolean;
|
||||||
target?: string[] | string; // TODO: some objects have an array and some are just strings, thanks bsg very cool
|
target?: string[] | string; // TODO: some objects have an array and some are just strings, thanks bsg very cool
|
||||||
completeInSeconds?: number
|
completeInSeconds?: number;
|
||||||
energy?: IValueCompare
|
energy?: IValueCompare;
|
||||||
exitName?: string;
|
exitName?: string;
|
||||||
hydration?: IValueCompare
|
hydration?: IValueCompare;
|
||||||
time?: IValueCompare
|
time?: IValueCompare;
|
||||||
compareMethod?: string;
|
compareMethod?: string;
|
||||||
value?: number;
|
value?: number;
|
||||||
weapon?: string[];
|
weapon?: string[];
|
||||||
distance?: ICounterConditionDistance
|
distance?: ICounterConditionDistance;
|
||||||
equipmentInclusive?: string[][];
|
equipmentInclusive?: string[][];
|
||||||
weaponModsInclusive?: string[][];
|
weaponModsInclusive?: string[][];
|
||||||
weaponModsExclusive?: string[][];
|
weaponModsExclusive?: string[][];
|
||||||
enemyEquipmentInclusive?: string[][];
|
enemyEquipmentInclusive?: string[][];
|
||||||
enemyEquipmentExclusive?: string[][];
|
enemyEquipmentExclusive?: string[][];
|
||||||
weaponCaliber?: string[]
|
weaponCaliber?: string[];
|
||||||
savageRole?: string[]
|
savageRole?: string[];
|
||||||
status?: string[];
|
status?: string[];
|
||||||
bodyPart?: string[];
|
bodyPart?: string[];
|
||||||
daytime?: IDaytimeCounter;
|
daytime?: IDaytimeCounter;
|
||||||
conditionType?: string
|
conditionType?: string;
|
||||||
enemyHealthEffects?: IEnemyHealthEffect[]
|
enemyHealthEffects?: IEnemyHealthEffect[];
|
||||||
resetOnSessionEnd?: boolean
|
resetOnSessionEnd?: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IEnemyHealthEffect
|
export interface IEnemyHealthEffect
|
||||||
{
|
{
|
||||||
bodyParts: string[]
|
bodyParts: string[];
|
||||||
effects: string[]
|
effects: string[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IValueCompare
|
export interface IValueCompare
|
||||||
{
|
{
|
||||||
compareMethod: string
|
compareMethod: string;
|
||||||
value: number
|
value: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICounterConditionDistance
|
export interface ICounterConditionDistance
|
||||||
{
|
{
|
||||||
value: number
|
value: number;
|
||||||
compareMethod: string
|
compareMethod: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IDaytimeCounter
|
export interface IDaytimeCounter
|
||||||
@ -142,7 +142,7 @@ export interface IDaytimeCounter
|
|||||||
export interface VisibilityCondition
|
export interface VisibilityCondition
|
||||||
{
|
{
|
||||||
id: string;
|
id: string;
|
||||||
target: string
|
target: string;
|
||||||
value?: number;
|
value?: number;
|
||||||
dynamicLocale?: boolean;
|
dynamicLocale?: boolean;
|
||||||
oneSessionOnly: boolean;
|
oneSessionOnly: boolean;
|
||||||
|
@ -2,9 +2,9 @@ import { IQuest, IQuestConditionTypes, IQuestRewards } from "./IQuest";
|
|||||||
|
|
||||||
export interface IRepeatableQuest extends IQuest
|
export interface IRepeatableQuest extends IQuest
|
||||||
{
|
{
|
||||||
changeCost: IChangeCost[]
|
changeCost: IChangeCost[];
|
||||||
changeStandingCost: number;
|
changeStandingCost: number;
|
||||||
sptRepatableGroupName: string
|
sptRepatableGroupName: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRepeatableQuestDatabase
|
export interface IRepeatableQuestDatabase
|
||||||
|
@ -86,7 +86,7 @@ export interface Props
|
|||||||
EffectiveDistance?: number;
|
EffectiveDistance?: number;
|
||||||
Ergonomics?: number;
|
Ergonomics?: number;
|
||||||
Velocity?: number;
|
Velocity?: number;
|
||||||
WithAnimatorAiming?: boolean
|
WithAnimatorAiming?: boolean;
|
||||||
RaidModdable?: boolean;
|
RaidModdable?: boolean;
|
||||||
ToolModdable?: boolean;
|
ToolModdable?: boolean;
|
||||||
UniqueAnimationModID?: number;
|
UniqueAnimationModID?: number;
|
||||||
@ -188,9 +188,9 @@ export interface Props
|
|||||||
weapUseType?: string;
|
weapUseType?: string;
|
||||||
ammoCaliber?: string;
|
ammoCaliber?: string;
|
||||||
OperatingResource?: number;
|
OperatingResource?: number;
|
||||||
PostRecoilHorizontalRangeHandRotation?: Ixyz
|
PostRecoilHorizontalRangeHandRotation?: Ixyz;
|
||||||
PostRecoilVerticalRangeHandRotation?: Ixyz
|
PostRecoilVerticalRangeHandRotation?: Ixyz;
|
||||||
ProgressRecoilAngleOnStable?: Ixyz
|
ProgressRecoilAngleOnStable?: Ixyz;
|
||||||
RepairComplexity?: number;
|
RepairComplexity?: number;
|
||||||
durabSpawnMin?: number;
|
durabSpawnMin?: number;
|
||||||
durabSpawnMax?: number;
|
durabSpawnMax?: number;
|
||||||
@ -198,7 +198,7 @@ export interface Props
|
|||||||
RecoilForceUp?: number;
|
RecoilForceUp?: number;
|
||||||
RecoilForceBack?: number;
|
RecoilForceBack?: number;
|
||||||
RecoilAngle?: number;
|
RecoilAngle?: number;
|
||||||
RecoilCamera?: number
|
RecoilCamera?: number;
|
||||||
weapFireType?: string[];
|
weapFireType?: string[];
|
||||||
RecolDispersion?: number;
|
RecolDispersion?: number;
|
||||||
SingleFireRate?: number;
|
SingleFireRate?: number;
|
||||||
@ -206,7 +206,7 @@ export interface Props
|
|||||||
bFirerate?: number;
|
bFirerate?: number;
|
||||||
bEffDist?: number;
|
bEffDist?: number;
|
||||||
bHearDist?: number;
|
bHearDist?: number;
|
||||||
blockLeftStance?: boolean
|
blockLeftStance?: boolean;
|
||||||
isChamberLoad?: boolean;
|
isChamberLoad?: boolean;
|
||||||
chamberAmmoCount?: number;
|
chamberAmmoCount?: number;
|
||||||
isBoltCatch?: boolean;
|
isBoltCatch?: boolean;
|
||||||
@ -216,8 +216,8 @@ export interface Props
|
|||||||
shotgunDispersion?: number;
|
shotgunDispersion?: number;
|
||||||
Chambers?: Slot[];
|
Chambers?: Slot[];
|
||||||
CameraSnap?: number;
|
CameraSnap?: number;
|
||||||
CameraToWeaponAngleSpeedRange?: Ixyz
|
CameraToWeaponAngleSpeedRange?: Ixyz;
|
||||||
CameraToWeaponAngleStep?: number
|
CameraToWeaponAngleStep?: number;
|
||||||
ReloadMode?: string;
|
ReloadMode?: string;
|
||||||
AimPlane?: number;
|
AimPlane?: number;
|
||||||
TacticalReloadStiffnes?: Ixyz;
|
TacticalReloadStiffnes?: Ixyz;
|
||||||
@ -225,7 +225,7 @@ export interface Props
|
|||||||
RecoilCenter?: Ixyz;
|
RecoilCenter?: Ixyz;
|
||||||
RotationCenter?: Ixyz;
|
RotationCenter?: Ixyz;
|
||||||
RotationCenterNoStock?: Ixyz;
|
RotationCenterNoStock?: Ixyz;
|
||||||
ShotsGroupSettings?: IShotsGroupSettings[]
|
ShotsGroupSettings?: IShotsGroupSettings[];
|
||||||
FoldedSlot?: string;
|
FoldedSlot?: string;
|
||||||
CompactHandling?: boolean;
|
CompactHandling?: boolean;
|
||||||
MinRepairDegradation?: number;
|
MinRepairDegradation?: number;
|
||||||
@ -257,11 +257,11 @@ export interface Props
|
|||||||
AllowOverheat?: boolean;
|
AllowOverheat?: boolean;
|
||||||
DoubleActionAccuracyPenalty?: number;
|
DoubleActionAccuracyPenalty?: number;
|
||||||
RecoilPosZMult?: number;
|
RecoilPosZMult?: number;
|
||||||
RecoilReturnPathDampingHandRotation?: number
|
RecoilReturnPathDampingHandRotation?: number;
|
||||||
RecoilReturnPathOffsetHandRotation?: number
|
RecoilReturnPathOffsetHandRotation?: number;
|
||||||
RecoilReturnSpeedHandRotation?: number
|
RecoilReturnSpeedHandRotation?: number;
|
||||||
RecoilStableAngleIncreaseStep?: number
|
RecoilStableAngleIncreaseStep?: number;
|
||||||
RecoilStableIndexShot?: number
|
RecoilStableIndexShot?: number;
|
||||||
MinRepairKitDegradation?: number;
|
MinRepairKitDegradation?: number;
|
||||||
MaxRepairKitDegradation?: number;
|
MaxRepairKitDegradation?: number;
|
||||||
BlocksEarpiece?: boolean;
|
BlocksEarpiece?: boolean;
|
||||||
@ -560,9 +560,9 @@ export interface IColor
|
|||||||
|
|
||||||
export interface IShotsGroupSettings
|
export interface IShotsGroupSettings
|
||||||
{
|
{
|
||||||
EndShotIndex: number
|
EndShotIndex: number;
|
||||||
ShotRecoilPositionStrength: Ixyz
|
ShotRecoilPositionStrength: Ixyz;
|
||||||
ShotRecoilRadianRange: Ixyz
|
ShotRecoilRadianRange: Ixyz;
|
||||||
ShotRecoilRotationStrength: Ixyz
|
ShotRecoilRotationStrength: Ixyz;
|
||||||
StartShotIndex: number
|
StartShotIndex: number;
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,5 @@
|
|||||||
export interface IGetRaidTimeRequest
|
export interface IGetRaidTimeRequest
|
||||||
{
|
{
|
||||||
Side: string,
|
Side: string;
|
||||||
Location: string
|
Location: string;
|
||||||
}
|
}
|
||||||
|
@ -1,15 +1,15 @@
|
|||||||
export interface IGetRaidTimeResponse
|
export interface IGetRaidTimeResponse
|
||||||
{
|
{
|
||||||
RaidTimeMinutes: number
|
RaidTimeMinutes: number;
|
||||||
NewSurviveTimeSeconds: number
|
NewSurviveTimeSeconds: number;
|
||||||
OriginalSurvivalTimeSeconds: number
|
OriginalSurvivalTimeSeconds: number;
|
||||||
ExitChanges: ExtractChange[]
|
ExitChanges: ExtractChange[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ExtractChange
|
export interface ExtractChange
|
||||||
{
|
{
|
||||||
Name: string
|
Name: string;
|
||||||
MinTime?: number
|
MinTime?: number;
|
||||||
MaxTime?: number
|
MaxTime?: number;
|
||||||
Chance?: number
|
Chance?: number;
|
||||||
}
|
}
|
||||||
|
@ -91,4 +91,4 @@ export interface StageBonus
|
|||||||
/** CHANGES PER DUMP */
|
/** CHANGES PER DUMP */
|
||||||
id?: string;
|
id?: string;
|
||||||
templateId?: string;
|
templateId?: string;
|
||||||
}
|
}
|
||||||
|
@ -17,27 +17,30 @@ export interface IQteData
|
|||||||
area: HideoutAreas;
|
area: HideoutAreas;
|
||||||
areaLevel: number;
|
areaLevel: number;
|
||||||
quickTimeEvents: IQuickTimeEvent[];
|
quickTimeEvents: IQuickTimeEvent[];
|
||||||
requirements: (IAreaRequirement
|
requirements:
|
||||||
| IItemRequirement
|
(
|
||||||
| ITraderUnlockRequirement
|
| IAreaRequirement
|
||||||
| ITraderLoyaltyRequirement
|
| IItemRequirement
|
||||||
| ISkillRequirement
|
| ITraderUnlockRequirement
|
||||||
| IResourceRequirement
|
| ITraderLoyaltyRequirement
|
||||||
| IToolRequirement
|
| ISkillRequirement
|
||||||
| IQuestRequirement
|
| IResourceRequirement
|
||||||
| IHealthRequirement
|
| IToolRequirement
|
||||||
| IBodyPartBuffRequirement)[];
|
| IQuestRequirement
|
||||||
|
| IHealthRequirement
|
||||||
|
| IBodyPartBuffRequirement
|
||||||
|
)[];
|
||||||
results: Record<QteEffectType, IQteResult>;
|
results: Record<QteEffectType, IQteResult>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IQuickTimeEvent
|
export interface IQuickTimeEvent
|
||||||
{
|
{
|
||||||
type: QteType;
|
type: QteType;
|
||||||
position: { x: number, y: number };
|
position: { x: number; y: number; };
|
||||||
startDelay: number;
|
startDelay: number;
|
||||||
endDelay: number;
|
endDelay: number;
|
||||||
speed: number;
|
speed: number;
|
||||||
successRange: { x: number, y: number };
|
successRange: { x: number; y: number; };
|
||||||
key: string;
|
key: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -71,73 +74,73 @@ export interface ISkillLevelMultiplier
|
|||||||
|
|
||||||
export interface IAreaRequirement extends IQteRequirement
|
export interface IAreaRequirement extends IQteRequirement
|
||||||
{
|
{
|
||||||
type: RequirementType.AREA,
|
type: RequirementType.AREA;
|
||||||
areaType: HideoutAreas,
|
areaType: HideoutAreas;
|
||||||
requiredLevel: number,
|
requiredLevel: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITraderUnlockRequirement extends IQteRequirement
|
export interface ITraderUnlockRequirement extends IQteRequirement
|
||||||
{
|
{
|
||||||
type: RequirementType.TRADER_UNLOCK,
|
type: RequirementType.TRADER_UNLOCK;
|
||||||
traderId: Traders;
|
traderId: Traders;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ITraderLoyaltyRequirement extends IQteRequirement
|
export interface ITraderLoyaltyRequirement extends IQteRequirement
|
||||||
{
|
{
|
||||||
type: RequirementType.TRADER_LOYALTY,
|
type: RequirementType.TRADER_LOYALTY;
|
||||||
traderId: Traders;
|
traderId: Traders;
|
||||||
loyaltyLevel: number;
|
loyaltyLevel: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISkillRequirement extends IQteRequirement
|
export interface ISkillRequirement extends IQteRequirement
|
||||||
{
|
{
|
||||||
type: RequirementType.SKILL,
|
type: RequirementType.SKILL;
|
||||||
skillName: SkillTypes;
|
skillName: SkillTypes;
|
||||||
skillLevel: number;
|
skillLevel: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IResourceRequirement extends IQteRequirement
|
export interface IResourceRequirement extends IQteRequirement
|
||||||
{
|
{
|
||||||
type: RequirementType.RESOURCE,
|
type: RequirementType.RESOURCE;
|
||||||
templateId: string,
|
templateId: string;
|
||||||
resource: number,
|
resource: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IItemRequirement extends IQteRequirement
|
export interface IItemRequirement extends IQteRequirement
|
||||||
{
|
{
|
||||||
type: RequirementType.ITEM,
|
type: RequirementType.ITEM;
|
||||||
templateId: string,
|
templateId: string;
|
||||||
count: number,
|
count: number;
|
||||||
isFunctional: boolean,
|
isFunctional: boolean;
|
||||||
isEncoded: boolean,
|
isEncoded: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IToolRequirement extends IQteRequirement
|
export interface IToolRequirement extends IQteRequirement
|
||||||
{
|
{
|
||||||
type: RequirementType.TOOL,
|
type: RequirementType.TOOL;
|
||||||
templateId: string,
|
templateId: string;
|
||||||
count: number,
|
count: number;
|
||||||
isFunctional: boolean,
|
isFunctional: boolean;
|
||||||
isEncoded: boolean,
|
isEncoded: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IQuestRequirement extends IQteRequirement
|
export interface IQuestRequirement extends IQteRequirement
|
||||||
{
|
{
|
||||||
type: RequirementType.QUEST_COMPLETE,
|
type: RequirementType.QUEST_COMPLETE;
|
||||||
questId: string,
|
questId: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IHealthRequirement extends IQteRequirement
|
export interface IHealthRequirement extends IQteRequirement
|
||||||
{
|
{
|
||||||
type: RequirementType.HEALTH,
|
type: RequirementType.HEALTH;
|
||||||
energy: number,
|
energy: number;
|
||||||
hydration: number,
|
hydration: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IBodyPartBuffRequirement extends IQteRequirement
|
export interface IBodyPartBuffRequirement extends IQteRequirement
|
||||||
{
|
{
|
||||||
type: RequirementType.BODY_PART_BUFF,
|
type: RequirementType.BODY_PART_BUFF;
|
||||||
effectName: Effect,
|
effectName: Effect;
|
||||||
bodyPart: BodyPart,
|
bodyPart: BodyPart;
|
||||||
excluded: boolean,
|
excluded: boolean;
|
||||||
}
|
}
|
||||||
|
@ -2,6 +2,6 @@ import { Item } from "../common/tables/IItem";
|
|||||||
|
|
||||||
export interface IItemDeliveryRequestData
|
export interface IItemDeliveryRequestData
|
||||||
{
|
{
|
||||||
items: Item[],
|
items: Item[];
|
||||||
traderId: string
|
traderId: string;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
import { Item } from "../common/tables/IItem"
|
import { Item } from "../common/tables/IItem";
|
||||||
|
|
||||||
export interface IAddItemDirectRequest
|
export interface IAddItemDirectRequest
|
||||||
{
|
{
|
||||||
@ -7,4 +7,4 @@ export interface IAddItemDirectRequest
|
|||||||
foundInRaid: boolean;
|
foundInRaid: boolean;
|
||||||
callback: (buyCount: number) => void;
|
callback: (buyCount: number) => void;
|
||||||
useSortingTable: boolean;
|
useSortingTable: boolean;
|
||||||
}
|
}
|
||||||
|
@ -9,4 +9,4 @@ export interface IAddItemsDirectRequest
|
|||||||
callback: (buyCount: number) => void;
|
callback: (buyCount: number) => void;
|
||||||
/** Should sorting table be used when no space found in stash */
|
/** Should sorting table be used when no space found in stash */
|
||||||
useSortingTable: boolean;
|
useSortingTable: boolean;
|
||||||
}
|
}
|
||||||
|
@ -1,8 +1,8 @@
|
|||||||
import { IInventoryBaseActionRequestData } from "@spt-aki/models/eft/inventory/IInventoryBaseActionRequestData";
|
import { IInventoryBaseActionRequestData } from "@spt-aki/models/eft/inventory/IInventoryBaseActionRequestData";
|
||||||
|
|
||||||
export interface IInventoryUnbindRequestData extends IInventoryBaseActionRequestData
|
export interface IInventoryUnbindRequestData extends IInventoryBaseActionRequestData
|
||||||
{
|
{
|
||||||
Action: "Unbind"
|
Action: "Unbind";
|
||||||
item: string
|
item: string;
|
||||||
index: number
|
index: number;
|
||||||
}
|
}
|
||||||
|
@ -3,11 +3,11 @@ import { IInventoryBaseActionRequestData } from "./IInventoryBaseActionRequestDa
|
|||||||
export interface IRedeemProfileRequestData extends IInventoryBaseActionRequestData
|
export interface IRedeemProfileRequestData extends IInventoryBaseActionRequestData
|
||||||
{
|
{
|
||||||
Action: "RedeemProfileReward";
|
Action: "RedeemProfileReward";
|
||||||
events: IRedeemProfileRequestEvent[]
|
events: IRedeemProfileRequestEvent[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRedeemProfileRequestEvent
|
export interface IRedeemProfileRequestEvent
|
||||||
{
|
{
|
||||||
MessageId: string
|
MessageId: string;
|
||||||
EventId: string
|
EventId: string;
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,5 @@ export interface ISetFavoriteItems extends IInventoryBaseActionRequestData
|
|||||||
{
|
{
|
||||||
Action: "SetFavoriteItems";
|
Action: "SetFavoriteItems";
|
||||||
items: any[];
|
items: any[];
|
||||||
timestamp: number
|
timestamp: number;
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,19 @@
|
|||||||
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory"
|
import { MemberCategory } from "@spt-aki/models/enums/MemberCategory";
|
||||||
|
|
||||||
export interface IGetGroupStatusResponse
|
export interface IGetGroupStatusResponse
|
||||||
{
|
{
|
||||||
players: IPlayer[]
|
players: IPlayer[];
|
||||||
maxPveCountExceeded: boolean
|
maxPveCountExceeded: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IPlayer
|
export interface IPlayer
|
||||||
{
|
{
|
||||||
aid: string
|
aid: string;
|
||||||
_id: string
|
_id: string;
|
||||||
lookingGroup: boolean
|
lookingGroup: boolean;
|
||||||
IsLeader: boolean
|
IsLeader: boolean;
|
||||||
IsReady: boolean
|
IsReady: boolean;
|
||||||
Info: ICurrentGroupMemberInfo
|
Info: ICurrentGroupMemberInfo;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ICurrentGroupMemberInfo
|
export interface ICurrentGroupMemberInfo
|
||||||
@ -22,4 +22,4 @@ export interface ICurrentGroupMemberInfo
|
|||||||
Side: string;
|
Side: string;
|
||||||
Level: string;
|
Level: string;
|
||||||
MemberCategory: MemberCategory;
|
MemberCategory: MemberCategory;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export interface IRemoveBuildRequestData
|
export interface IRemoveBuildRequestData
|
||||||
{
|
{
|
||||||
id: string;
|
id: string;
|
||||||
}
|
}
|
||||||
|
@ -7,7 +7,6 @@ import { IProfileChangeEvent } from "@spt-aki/models/spt/dialog/ISendMessageDeta
|
|||||||
|
|
||||||
export interface IAkiProfile
|
export interface IAkiProfile
|
||||||
{
|
{
|
||||||
|
|
||||||
info: Info;
|
info: Info;
|
||||||
characters: Characters;
|
characters: Characters;
|
||||||
/** Clothing purchases */
|
/** Clothing purchases */
|
||||||
@ -53,7 +52,7 @@ export interface IUserBuilds
|
|||||||
{
|
{
|
||||||
weaponBuilds: IWeaponBuild[];
|
weaponBuilds: IWeaponBuild[];
|
||||||
equipmentBuilds: IEquipmentBuild[];
|
equipmentBuilds: IEquipmentBuild[];
|
||||||
magazineBuilds: IMagazineBuild[]
|
magazineBuilds: IMagazineBuild[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IUserBuild
|
export interface IUserBuild
|
||||||
@ -64,7 +63,6 @@ export interface IUserBuild
|
|||||||
|
|
||||||
export interface IWeaponBuild extends IUserBuild
|
export interface IWeaponBuild extends IUserBuild
|
||||||
{
|
{
|
||||||
|
|
||||||
Root: string;
|
Root: string;
|
||||||
Items: Item[]; // Same as PMC inventory items
|
Items: Item[]; // Same as PMC inventory items
|
||||||
}
|
}
|
||||||
@ -78,25 +76,25 @@ export interface IEquipmentBuild extends IUserBuild
|
|||||||
|
|
||||||
export interface IMagazineBuild extends IUserBuild
|
export interface IMagazineBuild extends IUserBuild
|
||||||
{
|
{
|
||||||
Caliber: string
|
Caliber: string;
|
||||||
TopCount: number
|
TopCount: number;
|
||||||
BottomCount: number
|
BottomCount: number;
|
||||||
Items: IMagazineTemplateAmmoItem[]
|
Items: IMagazineTemplateAmmoItem[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IMagazineTemplateAmmoItem
|
export interface IMagazineTemplateAmmoItem
|
||||||
{
|
{
|
||||||
TemplateId: string
|
TemplateId: string;
|
||||||
Count: number
|
Count: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
/** Used by defaultEquipmentPresets.json */
|
/** Used by defaultEquipmentPresets.json */
|
||||||
export interface IDefaultEquipmentPreset extends IUserBuild
|
export interface IDefaultEquipmentPreset extends IUserBuild
|
||||||
{
|
{
|
||||||
Items: Item[]
|
Items: Item[];
|
||||||
Root: string
|
Root: string;
|
||||||
BuildType: EquipmentBuildType
|
BuildType: EquipmentBuildType;
|
||||||
type: string
|
type: string;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface Dialogue
|
export interface Dialogue
|
||||||
@ -291,8 +289,8 @@ export interface Insurance
|
|||||||
traderId: string;
|
traderId: string;
|
||||||
maxStorageTime: number;
|
maxStorageTime: number;
|
||||||
systemData: ISystemData;
|
systemData: ISystemData;
|
||||||
messageType: MessageType
|
messageType: MessageType;
|
||||||
messageTemplateId: string
|
messageTemplateId: string;
|
||||||
items: Item[];
|
items: Item[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export interface ICompletedAchievementsResponse
|
export interface ICompletedAchievementsResponse
|
||||||
{
|
{
|
||||||
elements: Record<string, number>
|
elements: Record<string, number>;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export interface ICreateProfileResponse
|
export interface ICreateProfileResponse
|
||||||
{
|
{
|
||||||
uid: string
|
uid: string;
|
||||||
}
|
}
|
||||||
|
@ -2,5 +2,5 @@ import { IAchievement } from "../common/tables/IAchievement";
|
|||||||
|
|
||||||
export interface IGetAchievementsResponse
|
export interface IGetAchievementsResponse
|
||||||
{
|
{
|
||||||
elements: IAchievement[]
|
elements: IAchievement[];
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export interface IGetOtherProfileRequest
|
export interface IGetOtherProfileRequest
|
||||||
{
|
{
|
||||||
accountId: string;
|
accountId: string;
|
||||||
}
|
}
|
||||||
|
@ -1,30 +1,29 @@
|
|||||||
|
import { OverallCounters, Skills } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||||
import { OverallCounters, Skills } from "@spt-aki/models/eft/common/tables/IBotBase"
|
import { Item } from "../common/tables/IItem";
|
||||||
import { Item } from "../common/tables/IItem"
|
|
||||||
|
|
||||||
export interface IGetOtherProfileResponse
|
export interface IGetOtherProfileResponse
|
||||||
{
|
{
|
||||||
id: string
|
id: string;
|
||||||
aid: number
|
aid: number;
|
||||||
info: IOtherProfileInfo
|
info: IOtherProfileInfo;
|
||||||
customization: IOtherProfileCustomization
|
customization: IOtherProfileCustomization;
|
||||||
skills: Skills
|
skills: Skills;
|
||||||
equipment: IOtherProfileEquipment
|
equipment: IOtherProfileEquipment;
|
||||||
achievements: Record<string, number>
|
achievements: Record<string, number>;
|
||||||
favoriteItems: string[]
|
favoriteItems: string[];
|
||||||
pmcStats: IOtherProfileStats
|
pmcStats: IOtherProfileStats;
|
||||||
scavStats: IOtherProfileStats
|
scavStats: IOtherProfileStats;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOtherProfileInfo
|
export interface IOtherProfileInfo
|
||||||
{
|
{
|
||||||
nickname: string
|
nickname: string;
|
||||||
side: string
|
side: string;
|
||||||
experience: number
|
experience: number;
|
||||||
memberCategory: number
|
memberCategory: number;
|
||||||
bannedState: boolean
|
bannedState: boolean;
|
||||||
bannedUntil: number
|
bannedUntil: number;
|
||||||
registrationDate: number
|
registrationDate: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IOtherProfileCustomization
|
export interface IOtherProfileCustomization
|
||||||
@ -48,6 +47,6 @@ export interface IOtherProfileStats
|
|||||||
|
|
||||||
export interface IOtherProfileSubStats
|
export interface IOtherProfileSubStats
|
||||||
{
|
{
|
||||||
totalInGameTime: number
|
totalInGameTime: number;
|
||||||
overAllCounters: OverallCounters
|
overAllCounters: OverallCounters;
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
export interface IGetRagfairOfferByIdRequest
|
export interface IGetRagfairOfferByIdRequest
|
||||||
{
|
{
|
||||||
id: number
|
id: number;
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,7 @@ export interface IWeatherData
|
|||||||
time: string;
|
time: string;
|
||||||
date: string;
|
date: string;
|
||||||
weather?: IWeather;
|
weather?: IWeather;
|
||||||
winterEventEnabled: boolean
|
winterEventEnabled: boolean;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IWeather
|
export interface IWeather
|
||||||
|
@ -103,6 +103,6 @@ export enum BaseClasses
|
|||||||
STACKABLE_ITEM = "5661632d4bdc2d903d8b456b",
|
STACKABLE_ITEM = "5661632d4bdc2d903d8b456b",
|
||||||
BUILT_IN_INSERTS = "65649eb40bf0ed77b8044453",
|
BUILT_IN_INSERTS = "65649eb40bf0ed77b8044453",
|
||||||
ARMOR_PLATE = "644120aa86ffbe10ee032b6f",
|
ARMOR_PLATE = "644120aa86ffbe10ee032b6f",
|
||||||
CULTIST_AMULET= "64b69b0c8f3be32ed22682f8",
|
CULTIST_AMULET = "64b69b0c8f3be32ed22682f8",
|
||||||
RADIO_TRANSMITTER = "62e9103049c018f425059f38"
|
RADIO_TRANSMITTER = "62e9103049c018f425059f38",
|
||||||
}
|
}
|
||||||
|
@ -4,5 +4,5 @@ export enum BonusSkillType
|
|||||||
COMBAT = "Combat",
|
COMBAT = "Combat",
|
||||||
SPECIAL = "Special",
|
SPECIAL = "Special",
|
||||||
PRACTICAL = "Practical",
|
PRACTICAL = "Practical",
|
||||||
MENTAL = "Mental"
|
MENTAL = "Mental",
|
||||||
}
|
}
|
||||||
|
@ -5,11 +5,11 @@ export enum BonusType
|
|||||||
HEALTH_REGENERATION = "HealthRegeneration",
|
HEALTH_REGENERATION = "HealthRegeneration",
|
||||||
EXPERIENCE_RATE = "ExperienceRate",
|
EXPERIENCE_RATE = "ExperienceRate",
|
||||||
QUEST_MONEY_REWARD = "QuestMoneyReward",
|
QUEST_MONEY_REWARD = "QuestMoneyReward",
|
||||||
SCAV_COOLDOWN_TIMER = "ScavCooldownTimer",
|
SCAV_COOLDOWN_TIMER = "ScavCooldownTimer",
|
||||||
UNLOCK_ITEM_CRAFT = "UnlockItemCraft",
|
UNLOCK_ITEM_CRAFT = "UnlockItemCraft",
|
||||||
UNLOCK_ITEM_PASSIVE_CREATION = "UnlockItemPassiveCreation",
|
UNLOCK_ITEM_PASSIVE_CREATION = "UnlockItemPassiveCreation",
|
||||||
UNLOCK_RANDOM_ITEM_CREATION = "UnlockRandomItemCreation",
|
UNLOCK_RANDOM_ITEM_CREATION = "UnlockRandomItemCreation",
|
||||||
SKILL_LEVELING_BOOST = "SkillLevelingBoost",
|
SKILL_LEVELING_BOOST = "SkillLevelingBoost",
|
||||||
DEBUFF_END_DELAY = "DebuffEndDelay",
|
DEBUFF_END_DELAY = "DebuffEndDelay",
|
||||||
RAGFAIR_COMMISSION = "RagfairCommission",
|
RAGFAIR_COMMISSION = "RagfairCommission",
|
||||||
INSURANCE_RETURN_TIME = "InsuranceReturnTime",
|
INSURANCE_RETURN_TIME = "InsuranceReturnTime",
|
||||||
@ -19,15 +19,15 @@ export enum BonusType
|
|||||||
UNLOCK_ITEM_CHARGE = "UnlockItemCharge",
|
UNLOCK_ITEM_CHARGE = "UnlockItemCharge",
|
||||||
RECEIVE_ITEM_BONUS = "ReceiveItemBonus",
|
RECEIVE_ITEM_BONUS = "ReceiveItemBonus",
|
||||||
UNLOCK_UNIQUE_ID = "UnlockUniqueId",
|
UNLOCK_UNIQUE_ID = "UnlockUniqueId",
|
||||||
INCREASE_CANISTER_SLOTS = "IncreaseCanisterSlots",
|
INCREASE_CANISTER_SLOTS = "IncreaseCanisterSlots",
|
||||||
ADDITIONAL_SLOTS = "AdditionalSlots",
|
ADDITIONAL_SLOTS = "AdditionalSlots",
|
||||||
FUEL_CONSUMPTION = "FuelConsumption",
|
FUEL_CONSUMPTION = "FuelConsumption",
|
||||||
REPAIR_WEAPON_BONUS = "RepairWeaponBonus",
|
REPAIR_WEAPON_BONUS = "RepairWeaponBonus",
|
||||||
REPAIR_ARMOR_BONUS = "RepairArmorBonus",
|
REPAIR_ARMOR_BONUS = "RepairArmorBonus",
|
||||||
UNLOCK_WEAPON_REPAIR = "UnlockWeaponRepair",
|
UNLOCK_WEAPON_REPAIR = "UnlockWeaponRepair",
|
||||||
UNLOCK_ARMOR_REPAIR = "UnlockArmorRepair",
|
UNLOCK_ARMOR_REPAIR = "UnlockArmorRepair",
|
||||||
STASH_SIZE = "StashSize",
|
STASH_SIZE = "StashSize",
|
||||||
MAXIMUM_ENERGY_RESERVE = "MaximumEnergyReserve",
|
MAXIMUM_ENERGY_RESERVE = "MaximumEnergyReserve",
|
||||||
TEXT_BONUS = "TextBonus",
|
TEXT_BONUS = "TextBonus",
|
||||||
SKILL_GROUP_LEVELING_BOOST = "SkillGroupLevelingBoost"
|
SKILL_GROUP_LEVELING_BOOST = "SkillGroupLevelingBoost",
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export enum ConfigTypes {
|
export enum ConfigTypes
|
||||||
|
{
|
||||||
AIRDROP = "aki-airdrop",
|
AIRDROP = "aki-airdrop",
|
||||||
BOT = "aki-bot",
|
BOT = "aki-bot",
|
||||||
PMC = "aki-pmc",
|
PMC = "aki-pmc",
|
||||||
@ -25,5 +26,5 @@ export enum ConfigTypes {
|
|||||||
SEASONAL_EVENT = "aki-seasonalevents",
|
SEASONAL_EVENT = "aki-seasonalevents",
|
||||||
LOST_ON_DEATH = "aki-lostondeath",
|
LOST_ON_DEATH = "aki-lostondeath",
|
||||||
GIFTS = "aki-gifts",
|
GIFTS = "aki-gifts",
|
||||||
BTR = "aki-btr"
|
BTR = "aki-btr",
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export enum HideoutAreas {
|
export enum HideoutAreas
|
||||||
|
{
|
||||||
NOTSET = -1,
|
NOTSET = -1,
|
||||||
VENTS = 0,
|
VENTS = 0,
|
||||||
SECURITY = 1,
|
SECURITY = 1,
|
||||||
@ -25,5 +26,5 @@ export enum HideoutAreas {
|
|||||||
EMERGENCY_WALL = 22,
|
EMERGENCY_WALL = 22,
|
||||||
GYM = 23,
|
GYM = 23,
|
||||||
WEAPON_STAND = 24,
|
WEAPON_STAND = 24,
|
||||||
WEAPON_STAND_SECONDARY = 25
|
WEAPON_STAND_SECONDARY = 25,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export enum ItemAddedResult {
|
export enum ItemAddedResult
|
||||||
|
{
|
||||||
UNKNOWN = -1,
|
UNKNOWN = -1,
|
||||||
SUCCESS = 1,
|
SUCCESS = 1,
|
||||||
NO_SPACE = 2,
|
NO_SPACE = 2,
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export enum ItemEventActions {
|
export enum ItemEventActions
|
||||||
|
{
|
||||||
MOVE = "Move",
|
MOVE = "Move",
|
||||||
REMOVE = "Remove",
|
REMOVE = "Remove",
|
||||||
SPLIT = "Split",
|
SPLIT = "Split",
|
||||||
@ -25,5 +26,5 @@ export enum ItemEventActions {
|
|||||||
REMOVE_EQUIPMENT_BUILD = "RemoveEquipmentBuild",
|
REMOVE_EQUIPMENT_BUILD = "RemoveEquipmentBuild",
|
||||||
REDEEM_PROFILE_REWARD = "RedeemProfileReward",
|
REDEEM_PROFILE_REWARD = "RedeemProfileReward",
|
||||||
SET_FAVORITE_ITEMS = "SetFavoriteItems",
|
SET_FAVORITE_ITEMS = "SetFavoriteItems",
|
||||||
QUEST_FAIL = "QuestFail"
|
QUEST_FAIL = "QuestFail",
|
||||||
}
|
}
|
||||||
|
@ -1,5 +1,6 @@
|
|||||||
export enum ModSpawn {
|
export enum ModSpawn
|
||||||
|
{
|
||||||
DEFAULT_MOD,
|
DEFAULT_MOD,
|
||||||
SPAWN,
|
SPAWN,
|
||||||
SKIP
|
SKIP,
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,5 @@ export enum SeasonalEventType
|
|||||||
HALLOWEEN = "Halloween",
|
HALLOWEEN = "Halloween",
|
||||||
NEW_YEARS = "NewYears",
|
NEW_YEARS = "NewYears",
|
||||||
PROMO = "Promo",
|
PROMO = "Promo",
|
||||||
SNOW = "Snow"
|
SNOW = "Snow",
|
||||||
}
|
}
|
||||||
|
@ -5,5 +5,5 @@ export enum TraderServiceType
|
|||||||
CULTISTS_AID = "CultistsAid",
|
CULTISTS_AID = "CultistsAid",
|
||||||
BTR_ITEMS_DELIVERY = "BtrItemsDelivery",
|
BTR_ITEMS_DELIVERY = "BtrItemsDelivery",
|
||||||
PLAYER_TAXI = "PlayerTaxi",
|
PLAYER_TAXI = "PlayerTaxi",
|
||||||
BTR_BOT_COVER = "BtrBotCover"
|
BTR_BOT_COVER = "BtrBotCover",
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export enum QteActivityType {
|
export enum QteActivityType
|
||||||
|
{
|
||||||
GYM = 0,
|
GYM = 0,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export enum QteEffectType {
|
export enum QteEffectType
|
||||||
|
{
|
||||||
FINISH_EFFECT = "FinishEffect",
|
FINISH_EFFECT = "FinishEffect",
|
||||||
SINGLE_SUCCESS_EFFECT = "SingleSuccessEffect",
|
SINGLE_SUCCESS_EFFECT = "SingleSuccessEffect",
|
||||||
SINGLE_FAIL_EFFECT = "SingleFailEffect",
|
SINGLE_FAIL_EFFECT = "SingleFailEffect",
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export enum QteResultType {
|
export enum QteResultType
|
||||||
|
{
|
||||||
NONE = "None",
|
NONE = "None",
|
||||||
EXIT = "Exit",
|
EXIT = "Exit",
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
export enum QteRewardType {
|
export enum QteRewardType
|
||||||
|
{
|
||||||
SKILL = "Skill",
|
SKILL = "Skill",
|
||||||
HEALTH_EFFECT = "HealthEffect",
|
HEALTH_EFFECT = "HealthEffect",
|
||||||
MUSCLE_PAIN = "MusclePain",
|
MUSCLE_PAIN = "MusclePain",
|
||||||
GYM_ARM_TRAUMA = "GymArmTrauma",
|
GYM_ARM_TRAUMA = "GymArmTrauma",
|
||||||
}
|
}
|
||||||
|
@ -1,3 +1,4 @@
|
|||||||
export enum QteType {
|
export enum QteType
|
||||||
|
{
|
||||||
SHRINKING_CIRCLE = 0,
|
SHRINKING_CIRCLE = 0,
|
||||||
}
|
}
|
||||||
|
@ -1,4 +1,5 @@
|
|||||||
export enum RequirementType {
|
export enum RequirementType
|
||||||
|
{
|
||||||
AREA = "Area",
|
AREA = "Area",
|
||||||
ITEM = "Item",
|
ITEM = "Item",
|
||||||
TRADER_UNLOCK = "TraderUnlock",
|
TRADER_UNLOCK = "TraderUnlock",
|
||||||
@ -9,4 +10,4 @@ export enum RequirementType {
|
|||||||
QUEST_COMPLETE = "QuestComplete",
|
QUEST_COMPLETE = "QuestComplete",
|
||||||
HEALTH = "Health",
|
HEALTH = "Health",
|
||||||
BODY_PART_BUFF = "BodyPartBuff",
|
BODY_PART_BUFF = "BodyPartBuff",
|
||||||
}
|
}
|
||||||
|
@ -5,4 +5,4 @@ export interface IChooseRandomCompatibleModResult
|
|||||||
chosenTpl?: string;
|
chosenTpl?: string;
|
||||||
reason: string;
|
reason: string;
|
||||||
slotBlocked?: boolean;
|
slotBlocked?: boolean;
|
||||||
}
|
}
|
||||||
|
@ -9,7 +9,7 @@ export interface IBTRConfig extends IBaseConfig
|
|||||||
/** How long the cover fire service lasts for */
|
/** How long the cover fire service lasts for */
|
||||||
coverFireTime: number;
|
coverFireTime: number;
|
||||||
/** How long the BTR waits at every point in its path */
|
/** How long the BTR waits at every point in its path */
|
||||||
pointWaitTime: MinMax,
|
pointWaitTime: MinMax;
|
||||||
/** How long after purchasing the taxi service before the BTR leaves */
|
/** How long after purchasing the taxi service before the BTR leaves */
|
||||||
taxiWaitTime: number;
|
taxiWaitTime: number;
|
||||||
}
|
}
|
||||||
|
@ -103,7 +103,7 @@ export interface EquipmentFilters
|
|||||||
/** Chance gun laser is active during the day */
|
/** Chance gun laser is active during the day */
|
||||||
laserIsActiveChancePercent?: number;
|
laserIsActiveChancePercent?: number;
|
||||||
/** Should plates be filtered by level */
|
/** Should plates be filtered by level */
|
||||||
filterPlatesByLevel?:boolean
|
filterPlatesByLevel?: boolean;
|
||||||
/** Chance NODS are down/active during the day */
|
/** Chance NODS are down/active during the day */
|
||||||
nvgIsActiveChanceDayPercent?: number;
|
nvgIsActiveChanceDayPercent?: number;
|
||||||
/** Chance NODS are down/active during the night */
|
/** Chance NODS are down/active during the night */
|
||||||
@ -121,7 +121,7 @@ export interface EquipmentFilters
|
|||||||
weightingAdjustmentsByPlayerLevel?: WeightingAdjustmentDetails[];
|
weightingAdjustmentsByPlayerLevel?: WeightingAdjustmentDetails[];
|
||||||
/** Should the stock mod be forced to spawn on bot */
|
/** Should the stock mod be forced to spawn on bot */
|
||||||
forceStock: boolean;
|
forceStock: boolean;
|
||||||
armorPlateWeighting?: IArmorPlateWeights[]
|
armorPlateWeighting?: IArmorPlateWeights[];
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ModLimits
|
export interface ModLimits
|
||||||
@ -169,7 +169,6 @@ export interface WeightingAdjustmentDetails
|
|||||||
equipment?: IAdjustmentDetails;
|
equipment?: IAdjustmentDetails;
|
||||||
/** Key: clothing slot e.g. feet, value: item tpl + weight */
|
/** Key: clothing slot e.g. feet, value: item tpl + weight */
|
||||||
clothing?: IAdjustmentDetails;
|
clothing?: IAdjustmentDetails;
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IAdjustmentDetails
|
export interface IAdjustmentDetails
|
||||||
|
@ -43,13 +43,13 @@ export interface ILocationConfig extends IBaseConfig
|
|||||||
/** Key: map, value: settings to control how long scav raids are*/
|
/** Key: map, value: settings to control how long scav raids are*/
|
||||||
scavRaidTimeSettings: IScavRaidTimeSettings;
|
scavRaidTimeSettings: IScavRaidTimeSettings;
|
||||||
/** Settings to adjust mods for lootable equipment in raid */
|
/** Settings to adjust mods for lootable equipment in raid */
|
||||||
equipmentLootSettings: IEquipmentLootSettings
|
equipmentLootSettings: IEquipmentLootSettings;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IEquipmentLootSettings
|
export interface IEquipmentLootSettings
|
||||||
{
|
{
|
||||||
// Percentage chance item will be added to equipment
|
// Percentage chance item will be added to equipment
|
||||||
modSpawnChancePercent: Record<string, number>
|
modSpawnChancePercent: Record<string, number>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IFixEmptyBotWavesSettings
|
export interface IFixEmptyBotWavesSettings
|
||||||
@ -118,13 +118,13 @@ export interface IContainerRandomistionSettings
|
|||||||
|
|
||||||
export interface IScavRaidTimeSettings
|
export interface IScavRaidTimeSettings
|
||||||
{
|
{
|
||||||
settings: IScavRaidTimeConfigSettings
|
settings: IScavRaidTimeConfigSettings;
|
||||||
maps: Record<string, IScavRaidTimeLocationSettings>
|
maps: Record<string, IScavRaidTimeLocationSettings>;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IScavRaidTimeConfigSettings
|
export interface IScavRaidTimeConfigSettings
|
||||||
{
|
{
|
||||||
trainArrivalDelayObservedSeconds: number
|
trainArrivalDelayObservedSeconds: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IScavRaidTimeLocationSettings
|
export interface IScavRaidTimeLocationSettings
|
||||||
@ -133,7 +133,7 @@ export interface IScavRaidTimeLocationSettings
|
|||||||
reduceLootByPercent: boolean;
|
reduceLootByPercent: boolean;
|
||||||
/** Smallest % of container loot that should be spawned */
|
/** Smallest % of container loot that should be spawned */
|
||||||
minStaticLootPercent: number;
|
minStaticLootPercent: number;
|
||||||
/** Smallest % of loose loot that should be spawned */
|
/** Smallest % of loose loot that should be spawned */
|
||||||
minDynamicLootPercent: number;
|
minDynamicLootPercent: number;
|
||||||
/** Chance raid time is reduced */
|
/** Chance raid time is reduced */
|
||||||
reducedChancePercent: number;
|
reducedChancePercent: number;
|
||||||
|
@ -77,8 +77,8 @@ export interface ITraderWhitelist
|
|||||||
traderId: string;
|
traderId: string;
|
||||||
questTypes: string[];
|
questTypes: string[];
|
||||||
rewardBaseWhitelist: string[];
|
rewardBaseWhitelist: string[];
|
||||||
rewardCanBeWeapon: boolean
|
rewardCanBeWeapon: boolean;
|
||||||
weaponRewardChancePercent: number
|
weaponRewardChancePercent: number;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRepeatableQuestTypesConfig
|
export interface IRepeatableQuestTypesConfig
|
||||||
@ -91,9 +91,9 @@ export interface IRepeatableQuestTypesConfig
|
|||||||
|
|
||||||
export interface IExploration extends IBaseQuestConfig
|
export interface IExploration extends IBaseQuestConfig
|
||||||
{
|
{
|
||||||
maxExtracts: number
|
maxExtracts: number;
|
||||||
maxExtractsWithSpecificExit: number
|
maxExtractsWithSpecificExit: number;
|
||||||
specificExits: ISpecificExits
|
specificExits: ISpecificExits;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface ISpecificExits
|
export interface ISpecificExits
|
||||||
@ -106,7 +106,7 @@ export interface ICompletion extends IBaseQuestConfig
|
|||||||
{
|
{
|
||||||
minRequestedAmount: number;
|
minRequestedAmount: number;
|
||||||
maxRequestedAmount: number;
|
maxRequestedAmount: number;
|
||||||
uniqueItemCount: number
|
uniqueItemCount: number;
|
||||||
minRequestedBulletAmount: number;
|
minRequestedBulletAmount: number;
|
||||||
maxRequestedBulletAmount: number;
|
maxRequestedBulletAmount: number;
|
||||||
useWhitelist: boolean;
|
useWhitelist: boolean;
|
||||||
|
@ -33,8 +33,8 @@ export interface ISendMessageDetails
|
|||||||
|
|
||||||
export interface IProfileChangeEvent
|
export interface IProfileChangeEvent
|
||||||
{
|
{
|
||||||
_id: string
|
_id: string;
|
||||||
Type: "TraderSalesSum" | "TraderStanding" | "ProfileLevel" | "SkillPoints" | "ExamineAllItems" | "UnlockTrader"
|
Type: "TraderSalesSum" | "TraderStanding" | "ProfileLevel" | "SkillPoints" | "ExamineAllItems" | "UnlockTrader";
|
||||||
value: number
|
value: number;
|
||||||
entity?: string
|
entity?: string;
|
||||||
}
|
}
|
||||||
|
@ -1,9 +1,9 @@
|
|||||||
export interface IRaidChanges
|
export interface IRaidChanges
|
||||||
{
|
{
|
||||||
/** What percentage of dynamic loot should the map contain */
|
/** What percentage of dynamic loot should the map contain */
|
||||||
dynamicLootPercent: number
|
dynamicLootPercent: number;
|
||||||
/** What percentage of static loot should the map contain */
|
/** What percentage of static loot should the map contain */
|
||||||
staticLootPercent: number
|
staticLootPercent: number;
|
||||||
/** How many seconds into the raid is the player simulated to spawn in at */
|
/** How many seconds into the raid is the player simulated to spawn in at */
|
||||||
simulatedRaidStartSeconds: number
|
simulatedRaidStartSeconds: number;
|
||||||
}
|
}
|
||||||
|
@ -55,7 +55,7 @@ export interface IDatabaseTables
|
|||||||
defaultEquipmentPresets: IDefaultEquipmentPreset[];
|
defaultEquipmentPresets: IDefaultEquipmentPreset[];
|
||||||
|
|
||||||
/** Achievements */
|
/** Achievements */
|
||||||
achievements: IAchievement[]
|
achievements: IAchievement[];
|
||||||
};
|
};
|
||||||
traders?: Record<string, ITrader>;
|
traders?: Record<string, ITrader>;
|
||||||
|
|
||||||
|
@ -2,7 +2,7 @@ import { TraderServiceType } from "@spt-aki/models/enums/TraderServiceType";
|
|||||||
|
|
||||||
export interface ITraderServiceModel
|
export interface ITraderServiceModel
|
||||||
{
|
{
|
||||||
serviceType: TraderServiceType,
|
serviceType: TraderServiceType;
|
||||||
itemsToPay?: Record<string, number>[],
|
itemsToPay?: Record<string, number>[];
|
||||||
subServices?: Record<string, number>[],
|
subServices?: Record<string, number>[];
|
||||||
}
|
}
|
||||||
|
@ -184,7 +184,7 @@ export class EventOutputHolder
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Return null if there's no crafts to send to client to match live behaviour
|
// Return null if there's no crafts to send to client to match live behaviour
|
||||||
return (Object.keys(productions).length > 0) ? productions : null
|
return (Object.keys(productions).length > 0) ? productions : null;
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -71,7 +71,7 @@ export class GameStaticRouter extends StaticRouter
|
|||||||
{
|
{
|
||||||
return this.gameCallbacks.getRaidTime(url, info, sessionID);
|
return this.gameCallbacks.getRaidTime(url, info, sessionID);
|
||||||
},
|
},
|
||||||
)
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -53,7 +53,7 @@ export class InraidStaticRouter extends StaticRouter
|
|||||||
(url: string, info: any, sessionID: string, output: string): any =>
|
(url: string, info: any, sessionID: string, output: string): any =>
|
||||||
{
|
{
|
||||||
return this.inraidCallbacks.itemDelivery(url, info, sessionID);
|
return this.inraidCallbacks.itemDelivery(url, info, sessionID);
|
||||||
}
|
},
|
||||||
),
|
),
|
||||||
]);
|
]);
|
||||||
}
|
}
|
||||||
|
@ -83,7 +83,11 @@ export class RagfairServer
|
|||||||
return Object.keys(this.ragfairConfig.traders).filter((x) => this.ragfairConfig.traders[x]);
|
return Object.keys(this.ragfairConfig.traders).filter((x) => this.ragfairConfig.traders[x]);
|
||||||
}
|
}
|
||||||
|
|
||||||
public getAllActiveCategories(fleaUnlocked: boolean, searchRequestData: ISearchRequestData, offers: IRagfairOffer[]): Record<string, number>
|
public getAllActiveCategories(
|
||||||
|
fleaUnlocked: boolean,
|
||||||
|
searchRequestData: ISearchRequestData,
|
||||||
|
offers: IRagfairOffer[],
|
||||||
|
): Record<string, number>
|
||||||
{
|
{
|
||||||
return this.ragfairCategoriesService.getCategoriesFromOffers(offers, searchRequestData, fleaUnlocked);
|
return this.ragfairCategoriesService.getCategoriesFromOffers(offers, searchRequestData, fleaUnlocked);
|
||||||
}
|
}
|
||||||
|
@ -27,7 +27,7 @@ export class SaveServer
|
|||||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||||
@inject("WinstonLogger") protected logger: ILogger,
|
@inject("WinstonLogger") protected logger: ILogger,
|
||||||
@inject("ConfigServer") protected configServer: ConfigServer
|
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||||
)
|
)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
@ -207,7 +207,10 @@ export class SaveServer
|
|||||||
}
|
}
|
||||||
|
|
||||||
const start = performance.now();
|
const start = performance.now();
|
||||||
const jsonProfile = this.jsonUtil.serialize(this.profiles[sessionID], !this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE).features.compressProfile);
|
const jsonProfile = this.jsonUtil.serialize(
|
||||||
|
this.profiles[sessionID],
|
||||||
|
!this.configServer.getConfig<ICoreConfig>(ConfigTypes.CORE).features.compressProfile,
|
||||||
|
);
|
||||||
const fmd5 = this.hashUtil.generateMd5ForData(jsonProfile);
|
const fmd5 = this.hashUtil.generateMd5ForData(jsonProfile);
|
||||||
if (typeof (this.saveMd5[sessionID]) !== "string" || this.saveMd5[sessionID] !== fmd5)
|
if (typeof (this.saveMd5[sessionID]) !== "string" || this.saveMd5[sessionID] !== fmd5)
|
||||||
{
|
{
|
||||||
|
@ -201,7 +201,13 @@ export class BotEquipmentModPoolService
|
|||||||
protected generateGearPool(): void
|
protected generateGearPool(): void
|
||||||
{
|
{
|
||||||
const gear = Object.values(this.databaseServer.getTables().templates.items).filter((x) =>
|
const gear = Object.values(this.databaseServer.getTables().templates.items).filter((x) =>
|
||||||
x._type === "Item" && this.itemHelper.isOfBaseclasses(x._id, [BaseClasses.ARMORED_EQUIPMENT, BaseClasses.VEST, BaseClasses.ARMOR, BaseClasses.HEADWEAR])
|
x._type === "Item"
|
||||||
|
&& this.itemHelper.isOfBaseclasses(x._id, [
|
||||||
|
BaseClasses.ARMORED_EQUIPMENT,
|
||||||
|
BaseClasses.VEST,
|
||||||
|
BaseClasses.ARMOR,
|
||||||
|
BaseClasses.HEADWEAR,
|
||||||
|
])
|
||||||
);
|
);
|
||||||
this.generatePool(gear, "gear");
|
this.generatePool(gear, "gear");
|
||||||
|
|
||||||
|
@ -408,9 +408,9 @@ export class FenceService
|
|||||||
{
|
{
|
||||||
const baseFenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort;
|
const baseFenceAssort = this.databaseServer.getTables().traders[Traders.FENCE].assort;
|
||||||
const itemTypeCounts = this.initItemLimitCounter(this.traderConfig.fence.itemTypeLimits);
|
const itemTypeCounts = this.initItemLimitCounter(this.traderConfig.fence.itemTypeLimits);
|
||||||
|
|
||||||
this.addItemAssorts(assortCount, assorts, baseFenceAssort, itemTypeCounts, loyaltyLevel);
|
this.addItemAssorts(assortCount, assorts, baseFenceAssort, itemTypeCounts, loyaltyLevel);
|
||||||
|
|
||||||
// Add presets
|
// Add presets
|
||||||
const maxPresetCount = Math.round(assortCount * (this.traderConfig.fence.maxPresetsPercent / 100));
|
const maxPresetCount = Math.round(assortCount * (this.traderConfig.fence.maxPresetsPercent / 100));
|
||||||
const randomisedPresetCount = this.randomUtil.getInt(0, maxPresetCount);
|
const randomisedPresetCount = this.randomUtil.getInt(0, maxPresetCount);
|
||||||
@ -426,17 +426,21 @@ export class FenceService
|
|||||||
): void
|
): void
|
||||||
{
|
{
|
||||||
const priceLimits = this.traderConfig.fence.itemCategoryRoublePriceLimit;
|
const priceLimits = this.traderConfig.fence.itemCategoryRoublePriceLimit;
|
||||||
const assortRootItems = baseFenceAssort.items.filter(x => x.parentId === "hideout" && !x.upd?.sptPresetId);
|
const assortRootItems = baseFenceAssort.items.filter((x) => x.parentId === "hideout" && !x.upd?.sptPresetId);
|
||||||
for (let i = 0; i < assortCount; i++)
|
for (let i = 0; i < assortCount; i++)
|
||||||
{
|
{
|
||||||
const chosenBaseAssortRoot = this.randomUtil.getArrayValue(assortRootItems);
|
const chosenBaseAssortRoot = this.randomUtil.getArrayValue(assortRootItems);
|
||||||
if (!chosenBaseAssortRoot)
|
if (!chosenBaseAssortRoot)
|
||||||
{
|
{
|
||||||
this.logger.error(this.localisationService.getText("fence-unable_to_find_assort_by_id", chosenBaseAssortRoot._id));
|
this.logger.error(
|
||||||
|
this.localisationService.getText("fence-unable_to_find_assort_by_id", chosenBaseAssortRoot._id),
|
||||||
|
);
|
||||||
|
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
const desiredAssortItemAndChildrenClone = this.jsonUtil.clone(this.itemHelper.findAndReturnChildrenAsItems(baseFenceAssort.items, chosenBaseAssortRoot._id));
|
const desiredAssortItemAndChildrenClone = this.jsonUtil.clone(
|
||||||
|
this.itemHelper.findAndReturnChildrenAsItems(baseFenceAssort.items, chosenBaseAssortRoot._id),
|
||||||
|
);
|
||||||
|
|
||||||
const itemDbDetails = this.itemHelper.getItem(chosenBaseAssortRoot._tpl)[1];
|
const itemDbDetails = this.itemHelper.getItem(chosenBaseAssortRoot._tpl)[1];
|
||||||
const itemLimitCount = itemTypeCounts[itemDbDetails._parent];
|
const itemLimitCount = itemTypeCounts[itemDbDetails._parent];
|
||||||
@ -446,7 +450,7 @@ export class FenceService
|
|||||||
i--;
|
i--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const itemIsPreset = this.presetHelper.isPreset(chosenBaseAssortRoot._id);
|
const itemIsPreset = this.presetHelper.isPreset(chosenBaseAssortRoot._id);
|
||||||
|
|
||||||
const price = baseFenceAssort.barter_scheme[chosenBaseAssortRoot._id][0][0].count;
|
const price = baseFenceAssort.barter_scheme[chosenBaseAssortRoot._id][0][0].count;
|
||||||
@ -456,7 +460,7 @@ export class FenceService
|
|||||||
i--;
|
i--;
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (price > priceLimits[itemDbDetails._parent])
|
if (price > priceLimits[itemDbDetails._parent])
|
||||||
{
|
{
|
||||||
// Too expensive for fence, try another item
|
// Too expensive for fence, try another item
|
||||||
@ -478,8 +482,8 @@ export class FenceService
|
|||||||
this.randomiseItemUpdProperties(itemDbDetails, rootItemBeingAdded);
|
this.randomiseItemUpdProperties(itemDbDetails, rootItemBeingAdded);
|
||||||
|
|
||||||
rootItemBeingAdded.upd.StackObjectsCount = this.getSingleItemStackCount(itemDbDetails);
|
rootItemBeingAdded.upd.StackObjectsCount = this.getSingleItemStackCount(itemDbDetails);
|
||||||
//rootItemBeingAdded.upd.BuyRestrictionCurrent = 0;
|
// rootItemBeingAdded.upd.BuyRestrictionCurrent = 0;
|
||||||
//rootItemBeingAdded.upd.UnlimitedCount = false;
|
// rootItemBeingAdded.upd.UnlimitedCount = false;
|
||||||
|
|
||||||
// Need to add mods to armors so they dont show as red in the trade screen
|
// Need to add mods to armors so they dont show as red in the trade screen
|
||||||
if (this.itemHelper.itemRequiresSoftInserts(rootItemBeingAdded._tpl))
|
if (this.itemHelper.itemRequiresSoftInserts(rootItemBeingAdded._tpl))
|
||||||
@ -495,12 +499,17 @@ export class FenceService
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Find presets in base fence assort and add desired number to 'assorts' parameter
|
* Find presets in base fence assort and add desired number to 'assorts' parameter
|
||||||
* @param desiredPresetCount
|
* @param desiredPresetCount
|
||||||
* @param assorts
|
* @param assorts
|
||||||
* @param baseFenceAssort
|
* @param baseFenceAssort
|
||||||
* @param loyaltyLevel Which loyalty level is required to see/buy item
|
* @param loyaltyLevel Which loyalty level is required to see/buy item
|
||||||
*/
|
*/
|
||||||
protected addPresetsToAssort(desiredPresetCount: number, assorts: ITraderAssort, baseFenceAssort: ITraderAssort, loyaltyLevel: number): void
|
protected addPresetsToAssort(
|
||||||
|
desiredPresetCount: number,
|
||||||
|
assorts: ITraderAssort,
|
||||||
|
baseFenceAssort: ITraderAssort,
|
||||||
|
loyaltyLevel: number,
|
||||||
|
): void
|
||||||
{
|
{
|
||||||
let presetsAddedCount = 0;
|
let presetsAddedCount = 0;
|
||||||
if (desiredPresetCount <= 0)
|
if (desiredPresetCount <= 0)
|
||||||
@ -508,12 +517,14 @@ export class FenceService
|
|||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
const presetRootItems = baseFenceAssort.items.filter(item => item.upd?.sptPresetId);
|
const presetRootItems = baseFenceAssort.items.filter((item) => item.upd?.sptPresetId);
|
||||||
while (presetsAddedCount < desiredPresetCount)
|
while (presetsAddedCount < desiredPresetCount)
|
||||||
{
|
{
|
||||||
const randomPresetRoot = this.randomUtil.getArrayValue(presetRootItems);
|
const randomPresetRoot = this.randomUtil.getArrayValue(presetRootItems);
|
||||||
const rootItemDb = this.itemHelper.getItem(randomPresetRoot._tpl)[1];
|
const rootItemDb = this.itemHelper.getItem(randomPresetRoot._tpl)[1];
|
||||||
const presetWithChildrenClone = this.jsonUtil.clone(this.itemHelper.findAndReturnChildrenAsItems(baseFenceAssort.items, randomPresetRoot._id));
|
const presetWithChildrenClone = this.jsonUtil.clone(
|
||||||
|
this.itemHelper.findAndReturnChildrenAsItems(baseFenceAssort.items, randomPresetRoot._id),
|
||||||
|
);
|
||||||
|
|
||||||
// Need to add mods to armors so they dont show as red in the trade screen
|
// Need to add mods to armors so they dont show as red in the trade screen
|
||||||
if (this.itemHelper.itemRequiresSoftInserts(randomPresetRoot._tpl))
|
if (this.itemHelper.itemRequiresSoftInserts(randomPresetRoot._tpl))
|
||||||
@ -557,7 +568,7 @@ export class FenceService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Check for and adjust soft insert durability values
|
// Check for and adjust soft insert durability values
|
||||||
const requiredSlots = itemDbDetails._props.Slots.filter(slot => slot._required);
|
const requiredSlots = itemDbDetails._props.Slots.filter((slot) => slot._required);
|
||||||
const hasRequiredSlots = requiredSlots.length > 0;
|
const hasRequiredSlots = requiredSlots.length > 0;
|
||||||
if (hasRequiredSlots)
|
if (hasRequiredSlots)
|
||||||
{
|
{
|
||||||
@ -566,7 +577,8 @@ export class FenceService
|
|||||||
const modItemDbDetails = this.itemHelper.getItem(requiredSlot._props.filters[0].Plate)[1];
|
const modItemDbDetails = this.itemHelper.getItem(requiredSlot._props.filters[0].Plate)[1];
|
||||||
const durabilityValues = this.getRandomisedArmorDurabilityValues(
|
const durabilityValues = this.getRandomisedArmorDurabilityValues(
|
||||||
modItemDbDetails,
|
modItemDbDetails,
|
||||||
this.traderConfig.fence.armorMaxDurabilityPercentMinMax);
|
this.traderConfig.fence.armorMaxDurabilityPercentMinMax,
|
||||||
|
);
|
||||||
const plateTpl = requiredSlot._props.filters[0].Plate; // `Plate` property appears to be the 'default' item for slot
|
const plateTpl = requiredSlot._props.filters[0].Plate; // `Plate` property appears to be the 'default' item for slot
|
||||||
if (plateTpl === "")
|
if (plateTpl === "")
|
||||||
{
|
{
|
||||||
@ -575,36 +587,41 @@ export class FenceService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Find items mod to apply dura changes to
|
// Find items mod to apply dura changes to
|
||||||
const modItemToAdjust = armor.find(mod => mod.slotId.toLowerCase() === requiredSlot._name.toLowerCase());
|
const modItemToAdjust = armor.find((mod) =>
|
||||||
|
mod.slotId.toLowerCase() === requiredSlot._name.toLowerCase()
|
||||||
|
);
|
||||||
if (!modItemToAdjust.upd)
|
if (!modItemToAdjust.upd)
|
||||||
{
|
{
|
||||||
modItemToAdjust.upd = {}
|
modItemToAdjust.upd = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!modItemToAdjust.upd.Repairable)
|
if (!modItemToAdjust.upd.Repairable)
|
||||||
{
|
{
|
||||||
modItemToAdjust.upd.Repairable = {
|
modItemToAdjust.upd.Repairable = {
|
||||||
Durability: modItemDbDetails._props.MaxDurability,
|
Durability: modItemDbDetails._props.MaxDurability,
|
||||||
MaxDurability: modItemDbDetails._props.MaxDurability
|
MaxDurability: modItemDbDetails._props.MaxDurability,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
modItemToAdjust.upd.Repairable.Durability = durabilityValues.Durability;
|
modItemToAdjust.upd.Repairable.Durability = durabilityValues.Durability;
|
||||||
modItemToAdjust.upd.Repairable.MaxDurability = durabilityValues.MaxDurability;
|
modItemToAdjust.upd.Repairable.MaxDurability = durabilityValues.MaxDurability;
|
||||||
|
|
||||||
// 25% chance to add shots to visor when its below max durability
|
// 25% chance to add shots to visor when its below max durability
|
||||||
if (this.randomUtil.getChance100(25)
|
if (
|
||||||
&& modItemToAdjust.parentId === BaseClasses.ARMORED_EQUIPMENT && modItemToAdjust.slotId === "mod_equipment_000"
|
this.randomUtil.getChance100(25)
|
||||||
&& modItemToAdjust.upd.Repairable.Durability < modItemDbDetails._props.MaxDurability) // Is damaged
|
&& modItemToAdjust.parentId === BaseClasses.ARMORED_EQUIPMENT
|
||||||
{
|
&& modItemToAdjust.slotId === "mod_equipment_000"
|
||||||
modItemToAdjust.upd.FaceShield = {
|
&& modItemToAdjust.upd.Repairable.Durability < modItemDbDetails._props.MaxDurability
|
||||||
Hits: this.randomUtil.getInt(1,3)
|
)
|
||||||
}
|
{ // Is damaged
|
||||||
|
modItemToAdjust.upd.FaceShield = { Hits: this.randomUtil.getInt(1, 3) };
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check for and adjust plate durability values
|
// Check for and adjust plate durability values
|
||||||
const plateSlots = itemDbDetails._props.Slots.filter(slot => this.itemHelper.isRemovablePlateSlot(slot._name));
|
const plateSlots = itemDbDetails._props.Slots.filter((slot) =>
|
||||||
|
this.itemHelper.isRemovablePlateSlot(slot._name)
|
||||||
|
);
|
||||||
if (plateSlots.length > 0)
|
if (plateSlots.length > 0)
|
||||||
{
|
{
|
||||||
for (const plateSlot of plateSlots)
|
for (const plateSlot of plateSlots)
|
||||||
@ -615,7 +632,7 @@ export class FenceService
|
|||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
const plateTpl = plateSlot._props.filters[0].Plate
|
const plateTpl = plateSlot._props.filters[0].Plate;
|
||||||
if (!plateTpl)
|
if (!plateTpl)
|
||||||
{
|
{
|
||||||
// Bsg data lacks a default plate, skip adding mod
|
// Bsg data lacks a default plate, skip adding mod
|
||||||
@ -624,20 +641,21 @@ export class FenceService
|
|||||||
const modItemDbDetails = this.itemHelper.getItem(plateTpl)[1];
|
const modItemDbDetails = this.itemHelper.getItem(plateTpl)[1];
|
||||||
const durabilityValues = this.getRandomisedArmorDurabilityValues(
|
const durabilityValues = this.getRandomisedArmorDurabilityValues(
|
||||||
modItemDbDetails,
|
modItemDbDetails,
|
||||||
this.traderConfig.fence.armorMaxDurabilityPercentMinMax);
|
this.traderConfig.fence.armorMaxDurabilityPercentMinMax,
|
||||||
|
);
|
||||||
|
|
||||||
// Find items mod to apply dura changes to
|
// Find items mod to apply dura changes to
|
||||||
const modItemToAdjust = armor.find(mod => mod.slotId.toLowerCase() === plateSlot._name.toLowerCase());
|
const modItemToAdjust = armor.find((mod) => mod.slotId.toLowerCase() === plateSlot._name.toLowerCase());
|
||||||
if (!modItemToAdjust.upd)
|
if (!modItemToAdjust.upd)
|
||||||
{
|
{
|
||||||
modItemToAdjust.upd = {}
|
modItemToAdjust.upd = {};
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!modItemToAdjust.upd.Repairable)
|
if (!modItemToAdjust.upd.Repairable)
|
||||||
{
|
{
|
||||||
modItemToAdjust.upd.Repairable = {
|
modItemToAdjust.upd.Repairable = {
|
||||||
Durability: modItemDbDetails._props.MaxDurability,
|
Durability: modItemDbDetails._props.MaxDurability,
|
||||||
MaxDurability: modItemDbDetails._props.MaxDurability
|
MaxDurability: modItemDbDetails._props.MaxDurability,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -755,11 +773,13 @@ export class FenceService
|
|||||||
if (
|
if (
|
||||||
(itemDetails._parent === BaseClasses.ARMORED_EQUIPMENT
|
(itemDetails._parent === BaseClasses.ARMORED_EQUIPMENT
|
||||||
|| itemDetails._parent === BaseClasses.FACECOVER
|
|| itemDetails._parent === BaseClasses.FACECOVER
|
||||||
|| itemDetails._parent === BaseClasses.ARMOR_PLATE
|
|| itemDetails._parent === BaseClasses.ARMOR_PLATE) && itemDetails._props.MaxDurability > 0
|
||||||
) && itemDetails._props.MaxDurability > 0
|
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
const values = this.getRandomisedArmorDurabilityValues(itemDetails, this.traderConfig.fence.armorMaxDurabilityPercentMinMax);
|
const values = this.getRandomisedArmorDurabilityValues(
|
||||||
|
itemDetails,
|
||||||
|
this.traderConfig.fence.armorMaxDurabilityPercentMinMax,
|
||||||
|
);
|
||||||
itemToAdjust.upd.Repairable = { Durability: values.Durability, MaxDurability: values.MaxDurability };
|
itemToAdjust.upd.Repairable = { Durability: values.Durability, MaxDurability: values.MaxDurability };
|
||||||
|
|
||||||
return;
|
return;
|
||||||
@ -816,7 +836,10 @@ export class FenceService
|
|||||||
* @param maxDurabilityMinMaxPercent Max durabiltiy percent min/max values
|
* @param maxDurabilityMinMaxPercent Max durabiltiy percent min/max values
|
||||||
* @returns Durability + MaxDurability values
|
* @returns Durability + MaxDurability values
|
||||||
*/
|
*/
|
||||||
protected getRandomisedArmorDurabilityValues(itemDetails: ITemplateItem, maxDurabilityMinMaxPercent: MinMax): Repairable
|
protected getRandomisedArmorDurabilityValues(
|
||||||
|
itemDetails: ITemplateItem,
|
||||||
|
maxDurabilityMinMaxPercent: MinMax,
|
||||||
|
): Repairable
|
||||||
{
|
{
|
||||||
const duraMin = maxDurabilityMinMaxPercent.min / 100 * itemDetails._props.MaxDurability;
|
const duraMin = maxDurabilityMinMaxPercent.min / 100 * itemDetails._props.MaxDurability;
|
||||||
const duraMax = maxDurabilityMinMaxPercent.max / 100 * itemDetails._props.MaxDurability;
|
const duraMax = maxDurabilityMinMaxPercent.max / 100 * itemDetails._props.MaxDurability;
|
||||||
@ -905,11 +928,11 @@ export class FenceService
|
|||||||
public amendOrRemoveFenceOffer(assortId: string, buyCount: number): void
|
public amendOrRemoveFenceOffer(assortId: string, buyCount: number): void
|
||||||
{
|
{
|
||||||
let isNormalAssort = true;
|
let isNormalAssort = true;
|
||||||
let fenceAssortItem = this.fenceAssort.items.find(item => item._id === assortId);
|
let fenceAssortItem = this.fenceAssort.items.find((item) => item._id === assortId);
|
||||||
if (!fenceAssortItem)
|
if (!fenceAssortItem)
|
||||||
{
|
{
|
||||||
// Not in main assorts, check secondary section
|
// Not in main assorts, check secondary section
|
||||||
fenceAssortItem = this.fenceDiscountAssort.items.find(item => item._id === assortId);
|
fenceAssortItem = this.fenceDiscountAssort.items.find((item) => item._id === assortId);
|
||||||
if (!fenceAssortItem)
|
if (!fenceAssortItem)
|
||||||
{
|
{
|
||||||
this.logger.error(`Offer with id: ${assortId} not found`);
|
this.logger.error(`Offer with id: ${assortId} not found`);
|
||||||
@ -937,7 +960,7 @@ export class FenceService
|
|||||||
const itemWithChildrenToRemove = this.itemHelper.findAndReturnChildrenAsItems(assorts, assortId);
|
const itemWithChildrenToRemove = this.itemHelper.findAndReturnChildrenAsItems(assorts, assortId);
|
||||||
for (const itemToRemove of itemWithChildrenToRemove)
|
for (const itemToRemove of itemWithChildrenToRemove)
|
||||||
{
|
{
|
||||||
let indexToRemove = assorts.findIndex(item => item._id === itemToRemove._id);
|
let indexToRemove = assorts.findIndex((item) => item._id === itemToRemove._id);
|
||||||
|
|
||||||
// No offer found in main assort, check discount items
|
// No offer found in main assort, check discount items
|
||||||
if (indexToRemove === -1)
|
if (indexToRemove === -1)
|
||||||
@ -947,7 +970,9 @@ export class FenceService
|
|||||||
|
|
||||||
if (indexToRemove === -1)
|
if (indexToRemove === -1)
|
||||||
{
|
{
|
||||||
this.logger.warning(`unable to remove fence assort item: ${itemToRemove._id} tpl: ${itemToRemove._tpl}`)
|
this.logger.warning(
|
||||||
|
`unable to remove fence assort item: ${itemToRemove._id} tpl: ${itemToRemove._tpl}`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
return;
|
return;
|
||||||
|
@ -137,7 +137,8 @@ export class GiftService
|
|||||||
senderDetails: {
|
senderDetails: {
|
||||||
_id: this.getSenderId(giftData),
|
_id: this.getSenderId(giftData),
|
||||||
aid: 1234567, // TODO - pass proper aid value
|
aid: 1234567, // TODO - pass proper aid value
|
||||||
Info: null },
|
Info: null,
|
||||||
|
},
|
||||||
messageText: giftData.messageText,
|
messageText: giftData.messageText,
|
||||||
items: giftData.items,
|
items: giftData.items,
|
||||||
itemsMaxStorageLifetimeSeconds: this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours),
|
itemsMaxStorageLifetimeSeconds: this.timeUtil.getHoursAsSeconds(giftData.collectionTimeHours),
|
||||||
|
@ -108,7 +108,7 @@ export class InsuranceService
|
|||||||
const systemData = {
|
const systemData = {
|
||||||
date: this.timeUtil.getDateMailFormat(),
|
date: this.timeUtil.getDateMailFormat(),
|
||||||
time: this.timeUtil.getTimeMailFormat(),
|
time: this.timeUtil.getTimeMailFormat(),
|
||||||
location: mapId
|
location: mapId,
|
||||||
};
|
};
|
||||||
// Send "i will go look for your stuff" message from trader to player
|
// Send "i will go look for your stuff" message from trader to player
|
||||||
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
this.mailSendService.sendLocalisedNpcMessageToPlayer(
|
||||||
@ -118,7 +118,7 @@ export class InsuranceService
|
|||||||
this.randomUtil.getArrayValue(dialogueTemplates.insuranceStart),
|
this.randomUtil.getArrayValue(dialogueTemplates.insuranceStart),
|
||||||
null,
|
null,
|
||||||
null,
|
null,
|
||||||
systemData
|
systemData,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Store insurance to send to player later in profile
|
// Store insurance to send to player later in profile
|
||||||
@ -247,7 +247,7 @@ export class InsuranceService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Item iterated on could have already been processed previously (as a child of another item)
|
// Item iterated on could have already been processed previously (as a child of another item)
|
||||||
if (equipmentToSendToPlayer.some(item => item.itemsToReturnToPlayer._id === insuredItem.itemId))
|
if (equipmentToSendToPlayer.some((item) => item.itemsToReturnToPlayer._id === insuredItem.itemId))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
@ -256,14 +256,17 @@ export class InsuranceService
|
|||||||
// Catches both events: player died with item on + player survived but dropped item in raid
|
// Catches both events: player died with item on + player survived but dropped item in raid
|
||||||
if (!offRaidGearHash[insuredItem.itemId] || playerDied)
|
if (!offRaidGearHash[insuredItem.itemId] || playerDied)
|
||||||
{
|
{
|
||||||
equipmentToSendToPlayer.push(
|
equipmentToSendToPlayer.push({
|
||||||
{
|
|
||||||
pmcData: pmcData,
|
pmcData: pmcData,
|
||||||
itemsToReturnToPlayer: this.getInsuredItemDetails(
|
itemsToReturnToPlayer: this.getInsuredItemDetails(
|
||||||
pmcData,
|
pmcData,
|
||||||
this.itemHelper.findAndReturnChildrenAsItems(Object.values(preRaidGearHash), preRaidItem._id, true),
|
this.itemHelper.findAndReturnChildrenAsItems(
|
||||||
offraidData.insurance,
|
Object.values(preRaidGearHash),
|
||||||
|
preRaidItem._id,
|
||||||
|
true,
|
||||||
),
|
),
|
||||||
|
offraidData.insurance,
|
||||||
|
),
|
||||||
traderId: insuredItem.tid,
|
traderId: insuredItem.tid,
|
||||||
sessionID: sessionID,
|
sessionID: sessionID,
|
||||||
});
|
});
|
||||||
@ -287,13 +290,13 @@ export class InsuranceService
|
|||||||
protected getInsuredItemDetails(
|
protected getInsuredItemDetails(
|
||||||
pmcData: IPmcData,
|
pmcData: IPmcData,
|
||||||
preRaidItemWithChildren: Item[],
|
preRaidItemWithChildren: Item[],
|
||||||
allItemsFromClient: IInsuredItemsData[]
|
allItemsFromClient: IInsuredItemsData[],
|
||||||
): Item[]
|
): Item[]
|
||||||
{
|
{
|
||||||
const itemsToReturn: Item[] = [];
|
const itemsToReturn: Item[] = [];
|
||||||
for (const preRaidItem of preRaidItemWithChildren)
|
for (const preRaidItem of preRaidItemWithChildren)
|
||||||
{
|
{
|
||||||
const isInsured = pmcData.InsuredItems.some(item => item.itemId === preRaidItem._id);
|
const isInsured = pmcData.InsuredItems.some((item) => item.itemId === preRaidItem._id);
|
||||||
const itemClientInsuranceData = allItemsFromClient?.find((x) => x.id === preRaidItem._id);
|
const itemClientInsuranceData = allItemsFromClient?.find((x) => x.id === preRaidItem._id);
|
||||||
const itemIsSoftInsert = this.itemHelper.isOfBaseclass(preRaidItem._tpl, BaseClasses.BUILT_IN_INSERTS);
|
const itemIsSoftInsert = this.itemHelper.isOfBaseclass(preRaidItem._tpl, BaseClasses.BUILT_IN_INSERTS);
|
||||||
|
|
||||||
@ -437,7 +440,7 @@ export class InsuranceService
|
|||||||
this.addInsuranceItemToArray(sessionId, traderId, itemsToReturnToPlayer);
|
this.addInsuranceItemToArray(sessionId, traderId, itemsToReturnToPlayer);
|
||||||
|
|
||||||
// Remove item from insured items array as its been processed
|
// Remove item from insured items array as its been processed
|
||||||
const returnedItemIds = itemsToReturnToPlayer.map(item => item._id);
|
const returnedItemIds = itemsToReturnToPlayer.map((item) => item._id);
|
||||||
pmcData.InsuredItems = pmcData.InsuredItems.filter((item) => !returnedItemIds.includes(item.itemId));
|
pmcData.InsuredItems = pmcData.InsuredItems.filter((item) => !returnedItemIds.includes(item.itemId));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -113,9 +113,7 @@ export class LocaleService
|
|||||||
return platformLocale.language;
|
return platformLocale.language;
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.warning(
|
this.logger.warning(`Unsupported system langauge found: ${localeCode}, falling back to english`);
|
||||||
`Unsupported system langauge found: ${localeCode}, falling back to english`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return "en";
|
return "en";
|
||||||
}
|
}
|
||||||
@ -140,9 +138,7 @@ export class LocaleService
|
|||||||
const langaugeCode = platformLocale.language.toLowerCase();
|
const langaugeCode = platformLocale.language.toLowerCase();
|
||||||
if (!this.localeConfig.serverSupportedLocales.includes(langaugeCode))
|
if (!this.localeConfig.serverSupportedLocales.includes(langaugeCode))
|
||||||
{
|
{
|
||||||
this.logger.warning(
|
this.logger.warning(`Unsupported system langauge found: ${langaugeCode}, falling back to english`);
|
||||||
`Unsupported system langauge found: ${langaugeCode}, falling back to english`,
|
|
||||||
);
|
|
||||||
|
|
||||||
return "en";
|
return "en";
|
||||||
}
|
}
|
||||||
|
@ -23,7 +23,6 @@ export class LocalisationService
|
|||||||
@inject("LocaleService") protected localeService: LocaleService,
|
@inject("LocaleService") protected localeService: LocaleService,
|
||||||
)
|
)
|
||||||
{
|
{
|
||||||
|
|
||||||
const localeFileDirectory = path.join(
|
const localeFileDirectory = path.join(
|
||||||
process.cwd(),
|
process.cwd(),
|
||||||
globalThis.G_RELEASE_CONFIGURATION
|
globalThis.G_RELEASE_CONFIGURATION
|
||||||
|
@ -17,7 +17,6 @@ export class MatchLocationService
|
|||||||
|
|
||||||
public createGroup(sessionID: string, info: ICreateGroupRequestData): any
|
public createGroup(sessionID: string, info: ICreateGroupRequestData): any
|
||||||
{
|
{
|
||||||
|
|
||||||
const account = this.saveServer.getProfile(sessionID).info;
|
const account = this.saveServer.getProfile(sessionID).info;
|
||||||
const groupID = "test";
|
const groupID = "test";
|
||||||
|
|
||||||
@ -31,13 +30,7 @@ export class MatchLocationService
|
|||||||
isSavage: false,
|
isSavage: false,
|
||||||
timeShift: "CURR",
|
timeShift: "CURR",
|
||||||
dt: this.timeUtil.getTimestamp(),
|
dt: this.timeUtil.getTimestamp(),
|
||||||
players: [{
|
players: [{ _id: account.id, region: "EUR", ip: "127.0.0.1", savageId: account.scavId, accessKeyId: "" }],
|
||||||
_id: account.id,
|
|
||||||
region: "EUR",
|
|
||||||
ip: "127.0.0.1",
|
|
||||||
savageId: account.scavId,
|
|
||||||
accessKeyId: "",
|
|
||||||
}],
|
|
||||||
customDataCenter: [],
|
customDataCenter: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -222,9 +222,7 @@ export class PaymentService
|
|||||||
const rootCurrencyReward = {
|
const rootCurrencyReward = {
|
||||||
_id: this.hashUtil.generate(),
|
_id: this.hashUtil.generate(),
|
||||||
_tpl: currency,
|
_tpl: currency,
|
||||||
upd: {
|
upd: { StackObjectsCount: calcAmount },
|
||||||
StackObjectsCount: calcAmount
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const rewards = this.itemHelper.splitStackIntoSeparateItems(rootCurrencyReward);
|
const rewards = this.itemHelper.splitStackIntoSeparateItems(rootCurrencyReward);
|
||||||
|
|
||||||
@ -234,7 +232,7 @@ export class PaymentService
|
|||||||
itemsWithModsToAdd: rewards,
|
itemsWithModsToAdd: rewards,
|
||||||
foundInRaid: false,
|
foundInRaid: false,
|
||||||
callback: null,
|
callback: null,
|
||||||
useSortingTable: true
|
useSortingTable: true,
|
||||||
};
|
};
|
||||||
this.inventoryHelper.addItemsToStash(sessionID, addItemToStashRequest, pmcData, output);
|
this.inventoryHelper.addItemsToStash(sessionID, addItemToStashRequest, pmcData, output);
|
||||||
}
|
}
|
||||||
|
@ -64,7 +64,7 @@ export class ProfileFixerService
|
|||||||
this.addMissingRepeatableQuestsProperty(pmcProfile);
|
this.addMissingRepeatableQuestsProperty(pmcProfile);
|
||||||
this.addLighthouseKeeperIfMissing(pmcProfile);
|
this.addLighthouseKeeperIfMissing(pmcProfile);
|
||||||
this.addUnlockedInfoObjectIfMissing(pmcProfile);
|
this.addUnlockedInfoObjectIfMissing(pmcProfile);
|
||||||
this.removeOrphanedQuests(pmcProfile);
|
this.removeOrphanedQuests(pmcProfile);
|
||||||
|
|
||||||
if (pmcProfile.Inventory)
|
if (pmcProfile.Inventory)
|
||||||
{
|
{
|
||||||
@ -243,13 +243,8 @@ export class ProfileFixerService
|
|||||||
if (!stashItem)
|
if (!stashItem)
|
||||||
{
|
{
|
||||||
// Stand inventory stash item doesnt exist, add it
|
// Stand inventory stash item doesnt exist, add it
|
||||||
pmcProfile.Inventory.items.push(
|
pmcProfile.Inventory.items.push({ _id: hideoutStandAreaDb._id, _tpl: stageCurrentAt.container });
|
||||||
{
|
stashItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandAreaDb._id);
|
||||||
_id: hideoutStandAreaDb._id,
|
|
||||||
_tpl: stageCurrentAt.container
|
|
||||||
}
|
|
||||||
)
|
|
||||||
stashItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandAreaDb._id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||||
@ -266,13 +261,8 @@ export class ProfileFixerService
|
|||||||
if (!stashSecondaryItem)
|
if (!stashSecondaryItem)
|
||||||
{
|
{
|
||||||
// Stand inventory stash item doesnt exist, add it
|
// Stand inventory stash item doesnt exist, add it
|
||||||
pmcProfile.Inventory.items.push(
|
pmcProfile.Inventory.items.push({ _id: hideoutStandSecondaryAreaDb._id, _tpl: stageCurrentAt.container });
|
||||||
{
|
stashSecondaryItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandSecondaryAreaDb._id);
|
||||||
_id: hideoutStandSecondaryAreaDb._id,
|
|
||||||
_tpl: stageCurrentAt.container
|
|
||||||
}
|
|
||||||
)
|
|
||||||
stashSecondaryItem = pmcProfile.Inventory.items?.find((x) => x._id === hideoutStandSecondaryAreaDb._id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||||
@ -330,13 +320,8 @@ export class ProfileFixerService
|
|||||||
if (!stashItem)
|
if (!stashItem)
|
||||||
{
|
{
|
||||||
// Stand inventory stash item doesnt exist, add it
|
// Stand inventory stash item doesnt exist, add it
|
||||||
pmcProfile.Inventory.items.push(
|
pmcProfile.Inventory.items.push({ _id: placeOfFameAreaDb._id, _tpl: stageCurrentlyAt.container });
|
||||||
{
|
stashItem = pmcProfile.Inventory.items?.find((x) => x._id === placeOfFameAreaDb._id);
|
||||||
_id: placeOfFameAreaDb._id,
|
|
||||||
_tpl: stageCurrentlyAt.container
|
|
||||||
}
|
|
||||||
)
|
|
||||||
stashItem = pmcProfile.Inventory.items?.find((x) => x._id === placeOfFameAreaDb._id)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
// `hideoutAreaStashes` has value related stash inventory items tpl doesnt match what's expected
|
||||||
@ -521,16 +506,22 @@ export class ProfileFixerService
|
|||||||
const taskConditionKeysToRemove: string[] = [];
|
const taskConditionKeysToRemove: string[] = [];
|
||||||
const activeRepeatableQuests = this.getActiveRepeatableQuests(pmcProfile.RepeatableQuests);
|
const activeRepeatableQuests = this.getActiveRepeatableQuests(pmcProfile.RepeatableQuests);
|
||||||
const achievements = this.databaseServer.getTables().templates.achievements;
|
const achievements = this.databaseServer.getTables().templates.achievements;
|
||||||
|
|
||||||
// Loop over TaskConditionCounters objects and add once we want to remove to counterKeysToRemove
|
// Loop over TaskConditionCounters objects and add once we want to remove to counterKeysToRemove
|
||||||
for (const [key, taskConditionCounter] of Object.entries(pmcProfile.TaskConditionCounters))
|
for (const [key, taskConditionCounter] of Object.entries(pmcProfile.TaskConditionCounters))
|
||||||
{
|
{
|
||||||
// Only check if profile has repeatable quests
|
// Only check if profile has repeatable quests
|
||||||
if (pmcProfile.RepeatableQuests && activeRepeatableQuests.length > 0)
|
if (pmcProfile.RepeatableQuests && activeRepeatableQuests.length > 0)
|
||||||
{
|
{
|
||||||
const existsInActiveRepeatableQuests = activeRepeatableQuests.some((quest) => quest._id === taskConditionCounter.sourceId);
|
const existsInActiveRepeatableQuests = activeRepeatableQuests.some((quest) =>
|
||||||
const existsInQuests = pmcProfile.Quests.some((quest) => quest.qid === taskConditionCounter.sourceId);
|
quest._id === taskConditionCounter.sourceId
|
||||||
const isAchievementTracker = achievements.some((quest) => quest.id === taskConditionCounter.sourceId);
|
);
|
||||||
|
const existsInQuests = pmcProfile.Quests.some((quest) =>
|
||||||
|
quest.qid === taskConditionCounter.sourceId
|
||||||
|
);
|
||||||
|
const isAchievementTracker = achievements.some((quest) =>
|
||||||
|
quest.id === taskConditionCounter.sourceId
|
||||||
|
);
|
||||||
|
|
||||||
// If task conditions id is neither in activeQuests, quests or achievements - it's stale and should be cleaned up
|
// If task conditions id is neither in activeQuests, quests or achievements - it's stale and should be cleaned up
|
||||||
if (!(existsInActiveRepeatableQuests || existsInQuests || isAchievementTracker))
|
if (!(existsInActiveRepeatableQuests || existsInQuests || isAchievementTracker))
|
||||||
@ -1119,7 +1110,7 @@ export class ProfileFixerService
|
|||||||
if (itemAJson === itemBJson)
|
if (itemAJson === itemBJson)
|
||||||
{
|
{
|
||||||
// Both items match, we can safely delete one
|
// Both items match, we can safely delete one
|
||||||
const indexOfItemToRemove = pmcProfile.Inventory.items.findIndex(x => x._id === key);
|
const indexOfItemToRemove = pmcProfile.Inventory.items.findIndex((x) => x._id === key);
|
||||||
pmcProfile.Inventory.items.splice(indexOfItemToRemove, 1);
|
pmcProfile.Inventory.items.splice(indexOfItemToRemove, 1);
|
||||||
this.logger.warning(`Deleted duplicate item: ${key}`);
|
this.logger.warning(`Deleted duplicate item: ${key}`);
|
||||||
}
|
}
|
||||||
@ -1127,10 +1118,10 @@ export class ProfileFixerService
|
|||||||
{
|
{
|
||||||
// Items are different, replace ID with unique value
|
// Items are different, replace ID with unique value
|
||||||
// Only replace ID if items have no children, we dont want orphaned children
|
// Only replace ID if items have no children, we dont want orphaned children
|
||||||
const itemsHaveChildren = pmcProfile.Inventory.items.some(x => x.parentId === key);
|
const itemsHaveChildren = pmcProfile.Inventory.items.some((x) => x.parentId === key);
|
||||||
if (!itemsHaveChildren)
|
if (!itemsHaveChildren)
|
||||||
{
|
{
|
||||||
const itemToAdjustId = pmcProfile.Inventory.items.find(x => x._id === key);
|
const itemToAdjustId = pmcProfile.Inventory.items.find((x) => x._id === key);
|
||||||
itemToAdjustId._id = this.hashUtil.generate();
|
itemToAdjustId._id = this.hashUtil.generate();
|
||||||
this.logger.warning(`Replace duplicate item Id: ${key} with ${itemToAdjustId._id}`);
|
this.logger.warning(`Replace duplicate item Id: ${key} with ${itemToAdjustId._id}`);
|
||||||
}
|
}
|
||||||
@ -1138,7 +1129,7 @@ export class ProfileFixerService
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Iterate over all inventory items
|
// Iterate over all inventory items
|
||||||
for (const item of pmcProfile.Inventory.items.filter(x => x.slotId))
|
for (const item of pmcProfile.Inventory.items.filter((x) => x.slotId))
|
||||||
{
|
{
|
||||||
if (!item.upd)
|
if (!item.upd)
|
||||||
{
|
{
|
||||||
@ -1151,7 +1142,7 @@ export class ProfileFixerService
|
|||||||
if (regxp.test(item.upd.Tag?.Name))
|
if (regxp.test(item.upd.Tag?.Name))
|
||||||
{
|
{
|
||||||
this.logger.warning(`Fixed item: ${item._id}s Tag value, removed invalid characters`);
|
this.logger.warning(`Fixed item: ${item._id}s Tag value, removed invalid characters`);
|
||||||
item.upd.Tag.Name = item.upd.Tag.Name.replace(regxp, '');
|
item.upd.Tag.Name = item.upd.Tag.Name.replace(regxp, "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Check items with StackObjectsCount (null)
|
// Check items with StackObjectsCount (null)
|
||||||
@ -1170,36 +1161,36 @@ export class ProfileFixerService
|
|||||||
// Check Head
|
// Check Head
|
||||||
if (!customizationDb[pmcProfile.Customization.Head])
|
if (!customizationDb[pmcProfile.Customization.Head])
|
||||||
{
|
{
|
||||||
const defaultHead = (playerIsUsec)
|
const defaultHead = playerIsUsec
|
||||||
? customizationDbArray.find(x => x._name === "DefaultUsecHead")
|
? customizationDbArray.find((x) => x._name === "DefaultUsecHead")
|
||||||
: customizationDbArray.find(x => x._name === "DefaultBearHead");
|
: customizationDbArray.find((x) => x._name === "DefaultBearHead");
|
||||||
pmcProfile.Customization.Head = defaultHead._id;
|
pmcProfile.Customization.Head = defaultHead._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check Body
|
// check Body
|
||||||
if (!customizationDb[pmcProfile.Customization.Body])
|
if (!customizationDb[pmcProfile.Customization.Body])
|
||||||
{
|
{
|
||||||
const defaultBody = (pmcProfile.Info.Side.toLowerCase() === "usec")
|
const defaultBody = (pmcProfile.Info.Side.toLowerCase() === "usec")
|
||||||
? customizationDbArray.find(x => x._name === "DefaultUsecBody")
|
? customizationDbArray.find((x) => x._name === "DefaultUsecBody")
|
||||||
: customizationDbArray.find(x => x._name === "DefaultBearBody");
|
: customizationDbArray.find((x) => x._name === "DefaultBearBody");
|
||||||
pmcProfile.Customization.Body = defaultBody._id;
|
pmcProfile.Customization.Body = defaultBody._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check Hands
|
// check Hands
|
||||||
if (!customizationDb[pmcProfile.Customization.Hands])
|
if (!customizationDb[pmcProfile.Customization.Hands])
|
||||||
{
|
{
|
||||||
const defaultHands = (pmcProfile.Info.Side.toLowerCase() === "usec")
|
const defaultHands = (pmcProfile.Info.Side.toLowerCase() === "usec")
|
||||||
? customizationDbArray.find(x => x._name === "DefaultUsecHands")
|
? customizationDbArray.find((x) => x._name === "DefaultUsecHands")
|
||||||
: customizationDbArray.find(x => x._name === "DefaultBearHands");
|
: customizationDbArray.find((x) => x._name === "DefaultBearHands");
|
||||||
pmcProfile.Customization.Hands = defaultHands._id;
|
pmcProfile.Customization.Hands = defaultHands._id;
|
||||||
}
|
}
|
||||||
|
|
||||||
//check Hands
|
// check Hands
|
||||||
if (!customizationDb[pmcProfile.Customization.Feet])
|
if (!customizationDb[pmcProfile.Customization.Feet])
|
||||||
{
|
{
|
||||||
const defaultFeet = (pmcProfile.Info.Side.toLowerCase() === "usec")
|
const defaultFeet = (pmcProfile.Info.Side.toLowerCase() === "usec")
|
||||||
? customizationDbArray.find(x => x._name === "DefaultUsecFeet")
|
? customizationDbArray.find((x) => x._name === "DefaultUsecFeet")
|
||||||
: customizationDbArray.find(x => x._name === "DefaultBearFeet");
|
: customizationDbArray.find((x) => x._name === "DefaultBearFeet");
|
||||||
pmcProfile.Customization.Feet = defaultFeet._id;
|
pmcProfile.Customization.Feet = defaultFeet._id;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -1276,7 +1267,7 @@ export class ProfileFixerService
|
|||||||
{
|
{
|
||||||
// Not a number, regenerate
|
// Not a number, regenerate
|
||||||
// biome-ignore lint/suspicious/noGlobalIsNan: <value can be a valid string, Number.IsNaN() would ignore it>
|
// biome-ignore lint/suspicious/noGlobalIsNan: <value can be a valid string, Number.IsNaN() would ignore it>
|
||||||
if (isNaN(fullProfile.characters.pmc.aid) || !fullProfile.info.aid)
|
if (isNaN(fullProfile.characters.pmc.aid) || !fullProfile.info.aid)
|
||||||
{
|
{
|
||||||
fullProfile.characters.pmc.sessionId = <string><unknown>fullProfile.characters.pmc.aid;
|
fullProfile.characters.pmc.sessionId = <string><unknown>fullProfile.characters.pmc.aid;
|
||||||
fullProfile.characters.pmc.aid = this.hashUtil.generateAccountId();
|
fullProfile.characters.pmc.aid = this.hashUtil.generateAccountId();
|
||||||
@ -1371,28 +1362,28 @@ export class ProfileFixerService
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* After removing mods that add quests, the quest panel will break without removing these
|
* After removing mods that add quests, the quest panel will break without removing these
|
||||||
* @param pmcProfile Profile to remove dead quests from
|
* @param pmcProfile Profile to remove dead quests from
|
||||||
*/
|
*/
|
||||||
protected removeOrphanedQuests(pmcProfile: IPmcData): void
|
protected removeOrphanedQuests(pmcProfile: IPmcData): void
|
||||||
{
|
{
|
||||||
const quests = this.databaseServer.getTables().templates.quests;
|
const quests = this.databaseServer.getTables().templates.quests;
|
||||||
const profileQuests = pmcProfile.Quests;
|
const profileQuests = pmcProfile.Quests;
|
||||||
|
|
||||||
const repeatableQuests: IRepeatableQuest[] = [];
|
const repeatableQuests: IRepeatableQuest[] = [];
|
||||||
for (const repeatableQuestType of pmcProfile.RepeatableQuests)
|
for (const repeatableQuestType of pmcProfile.RepeatableQuests)
|
||||||
{
|
{
|
||||||
repeatableQuests.push(...repeatableQuestType.activeQuests);
|
repeatableQuests.push(...repeatableQuestType.activeQuests);
|
||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < profileQuests.length; i++)
|
for (let i = 0; i < profileQuests.length; i++)
|
||||||
{
|
{
|
||||||
if (!quests[profileQuests[i].qid] && !repeatableQuests.find(x => x._id == profileQuests[i].qid))
|
if (!quests[profileQuests[i].qid] && !repeatableQuests.find((x) => x._id == profileQuests[i].qid))
|
||||||
{
|
{
|
||||||
profileQuests.splice(i, 1);
|
profileQuests.splice(i, 1);
|
||||||
this.logger.success("Successfully removed orphaned quest that doesnt exist in our quest data");
|
this.logger.success("Successfully removed orphaned quest that doesnt exist in our quest data");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -22,46 +22,53 @@ export class RagfairCategoriesService
|
|||||||
* @param fleaUnlocked Can player see full flea yet (level 15 by default)
|
* @param fleaUnlocked Can player see full flea yet (level 15 by default)
|
||||||
* @returns KVP of item tpls + count of offers
|
* @returns KVP of item tpls + count of offers
|
||||||
*/
|
*/
|
||||||
public getCategoriesFromOffers(offers: IRagfairOffer[], searchRequestData: ISearchRequestData, fleaUnlocked: boolean): Record<string, number>
|
public getCategoriesFromOffers(
|
||||||
|
offers: IRagfairOffer[],
|
||||||
|
searchRequestData: ISearchRequestData,
|
||||||
|
fleaUnlocked: boolean,
|
||||||
|
): Record<string, number>
|
||||||
{
|
{
|
||||||
// Get offers valid for search request, then reduce them down to just the counts
|
// Get offers valid for search request, then reduce them down to just the counts
|
||||||
return offers.filter(offer =>
|
return offers.filter((offer) =>
|
||||||
{
|
{
|
||||||
const isTraderOffer = offer.user.memberType === MemberCategory.TRADER;
|
const isTraderOffer = offer.user.memberType === MemberCategory.TRADER;
|
||||||
|
|
||||||
// Not level 15 and offer is from player, skip
|
// Not level 15 and offer is from player, skip
|
||||||
if (!fleaUnlocked && !isTraderOffer)
|
if (!fleaUnlocked && !isTraderOffer)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove items not for money when `removeBartering` is enabled
|
// Remove items not for money when `removeBartering` is enabled
|
||||||
if (searchRequestData.removeBartering && (offer.requirements.length > 1 || !this.paymentHelper.isMoneyTpl(offer.requirements[0]._tpl)))
|
if (
|
||||||
{
|
searchRequestData.removeBartering
|
||||||
return false;
|
&& (offer.requirements.length > 1 || !this.paymentHelper.isMoneyTpl(offer.requirements[0]._tpl))
|
||||||
}
|
)
|
||||||
|
{
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
// Remove when filter set to players only + offer is from trader
|
// Remove when filter set to players only + offer is from trader
|
||||||
if (searchRequestData.offerOwnerType === OfferOwnerType.PLAYEROWNERTYPE && isTraderOffer)
|
if (searchRequestData.offerOwnerType === OfferOwnerType.PLAYEROWNERTYPE && isTraderOffer)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Remove when filter set to traders only + offer is not from trader
|
// Remove when filter set to traders only + offer is not from trader
|
||||||
if (searchRequestData.offerOwnerType === OfferOwnerType.TRADEROWNERTYPE && !isTraderOffer)
|
if (searchRequestData.offerOwnerType === OfferOwnerType.TRADEROWNERTYPE && !isTraderOffer)
|
||||||
{
|
{
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Passed checks, its a valid offer to process
|
// Passed checks, its a valid offer to process
|
||||||
return true;
|
return true;
|
||||||
}).reduce((acc, offer) =>
|
}).reduce((acc, offer) =>
|
||||||
{
|
{
|
||||||
const itemTpl = offer.items[0]._tpl;
|
const itemTpl = offer.items[0]._tpl;
|
||||||
// Increment the category or add if doesnt exist
|
// Increment the category or add if doesnt exist
|
||||||
acc[itemTpl] = (acc[itemTpl] || 0) + 1;
|
acc[itemTpl] = (acc[itemTpl] || 0) + 1;
|
||||||
|
|
||||||
return acc;
|
return acc;
|
||||||
}, {});
|
}, {});
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -243,7 +243,9 @@ export class RagfairOfferService
|
|||||||
const offerinProfileIndex = profile.RagfairInfo.offers.findIndex((o) => o._id === playerOffer._id);
|
const offerinProfileIndex = profile.RagfairInfo.offers.findIndex((o) => o._id === playerOffer._id);
|
||||||
if (offerinProfileIndex === -1)
|
if (offerinProfileIndex === -1)
|
||||||
{
|
{
|
||||||
this.logger.warning(this.localisationService.getText("ragfair-unable_to_find_offer_to_remove", playerOffer._id));
|
this.logger.warning(
|
||||||
|
this.localisationService.getText("ragfair-unable_to_find_offer_to_remove", playerOffer._id),
|
||||||
|
);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,12 +401,12 @@ export class RagfairPriceService implements OnLoad
|
|||||||
*/
|
*/
|
||||||
protected getWeaponPreset(weapon: Item): { isDefault: boolean; preset: IPreset; }
|
protected getWeaponPreset(weapon: Item): { isDefault: boolean; preset: IPreset; }
|
||||||
{
|
{
|
||||||
const defaultPreset = this.presetHelper.getDefaultPreset(weapon._tpl)
|
const defaultPreset = this.presetHelper.getDefaultPreset(weapon._tpl);
|
||||||
if (defaultPreset)
|
if (defaultPreset)
|
||||||
{
|
{
|
||||||
return { isDefault: true, preset: defaultPreset };
|
return { isDefault: true, preset: defaultPreset };
|
||||||
}
|
}
|
||||||
const nonDefaultPresets = this.presetHelper.getPresets(weapon._tpl)
|
const nonDefaultPresets = this.presetHelper.getPresets(weapon._tpl);
|
||||||
if (nonDefaultPresets.length === 1)
|
if (nonDefaultPresets.length === 1)
|
||||||
{
|
{
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
|
@ -43,9 +43,9 @@ export class RagfairTaxService
|
|||||||
// It's structured to resemble the client-side code as closely as possible - avoid making any big structure changes if it's not necessary.
|
// It's structured to resemble the client-side code as closely as possible - avoid making any big structure changes if it's not necessary.
|
||||||
* @param item Item being sold on flea
|
* @param item Item being sold on flea
|
||||||
* @param pmcData player profile
|
* @param pmcData player profile
|
||||||
* @param requirementsValue
|
* @param requirementsValue
|
||||||
* @param offerItemCount Number of offers being created
|
* @param offerItemCount Number of offers being created
|
||||||
* @param sellInOnePiece
|
* @param sellInOnePiece
|
||||||
* @returns Tax in roubles
|
* @returns Tax in roubles
|
||||||
*/
|
*/
|
||||||
public calculateTax(
|
public calculateTax(
|
||||||
|
@ -7,7 +7,11 @@ import { ILocationBase } from "@spt-aki/models/eft/common/ILocationBase";
|
|||||||
import { IGetRaidTimeRequest } from "@spt-aki/models/eft/game/IGetRaidTimeRequest";
|
import { IGetRaidTimeRequest } from "@spt-aki/models/eft/game/IGetRaidTimeRequest";
|
||||||
import { ExtractChange, IGetRaidTimeResponse } from "@spt-aki/models/eft/game/IGetRaidTimeResponse";
|
import { ExtractChange, IGetRaidTimeResponse } from "@spt-aki/models/eft/game/IGetRaidTimeResponse";
|
||||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||||
import { ILocationConfig, IScavRaidTimeLocationSettings, LootMultiplier } from "@spt-aki/models/spt/config/ILocationConfig";
|
import {
|
||||||
|
ILocationConfig,
|
||||||
|
IScavRaidTimeLocationSettings,
|
||||||
|
LootMultiplier,
|
||||||
|
} from "@spt-aki/models/spt/config/ILocationConfig";
|
||||||
import { IRaidChanges } from "@spt-aki/models/spt/location/IRaidChanges";
|
import { IRaidChanges } from "@spt-aki/models/spt/location/IRaidChanges";
|
||||||
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
|
||||||
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
import { ConfigServer } from "@spt-aki/servers/ConfigServer";
|
||||||
@ -39,7 +43,9 @@ export class RaidTimeAdjustmentService
|
|||||||
*/
|
*/
|
||||||
public makeAdjustmentsToMap(raidAdjustments: IRaidChanges, mapBase: ILocationBase): void
|
public makeAdjustmentsToMap(raidAdjustments: IRaidChanges, mapBase: ILocationBase): void
|
||||||
{
|
{
|
||||||
this.logger.debug(`Adjusting dynamic loot multipliers to ${raidAdjustments.dynamicLootPercent}% and static loot multipliers to ${raidAdjustments.staticLootPercent}% of original`);
|
this.logger.debug(
|
||||||
|
`Adjusting dynamic loot multipliers to ${raidAdjustments.dynamicLootPercent}% and static loot multipliers to ${raidAdjustments.staticLootPercent}% of original`,
|
||||||
|
);
|
||||||
|
|
||||||
// Change loot multipler values before they're used below
|
// Change loot multipler values before they're used below
|
||||||
this.adjustLootMultipliers(this.locationConfig.looseLootMultiplier, raidAdjustments.dynamicLootPercent);
|
this.adjustLootMultipliers(this.locationConfig.looseLootMultiplier, raidAdjustments.dynamicLootPercent);
|
||||||
@ -48,8 +54,8 @@ export class RaidTimeAdjustmentService
|
|||||||
const mapSettings = this.getMapSettings(mapBase.Id);
|
const mapSettings = this.getMapSettings(mapBase.Id);
|
||||||
if (mapSettings.adjustWaves)
|
if (mapSettings.adjustWaves)
|
||||||
{
|
{
|
||||||
// Make alterations to bot spawn waves now player is simulated spawning later
|
// Make alterations to bot spawn waves now player is simulated spawning later
|
||||||
this.adjustWaves(mapBase, raidAdjustments)
|
this.adjustWaves(mapBase, raidAdjustments);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -75,7 +81,7 @@ export class RaidTimeAdjustmentService
|
|||||||
{
|
{
|
||||||
// Remove waves that spawned before the player joined
|
// Remove waves that spawned before the player joined
|
||||||
const originalWaveCount = mapBase.waves.length;
|
const originalWaveCount = mapBase.waves.length;
|
||||||
mapBase.waves = mapBase.waves.filter(x => x.time_max > raidAdjustments.simulatedRaidStartSeconds);
|
mapBase.waves = mapBase.waves.filter((x) => x.time_max > raidAdjustments.simulatedRaidStartSeconds);
|
||||||
|
|
||||||
// Adjust wave min/max times to match new simulated start
|
// Adjust wave min/max times to match new simulated start
|
||||||
for (const wave of mapBase.waves)
|
for (const wave of mapBase.waves)
|
||||||
@ -85,7 +91,11 @@ export class RaidTimeAdjustmentService
|
|||||||
wave.time_max -= Math.max(raidAdjustments.simulatedRaidStartSeconds, 0);
|
wave.time_max -= Math.max(raidAdjustments.simulatedRaidStartSeconds, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
this.logger.debug(`Removed ${originalWaveCount - mapBase.waves.length} wave from map due to simulated raid start time of ${raidAdjustments.simulatedRaidStartSeconds / 60} minutes`);
|
this.logger.debug(
|
||||||
|
`Removed ${originalWaveCount - mapBase.waves.length} wave from map due to simulated raid start time of ${
|
||||||
|
raidAdjustments.simulatedRaidStartSeconds / 60
|
||||||
|
} minutes`,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -106,8 +116,8 @@ export class RaidTimeAdjustmentService
|
|||||||
RaidTimeMinutes: baseEscapeTimeMinutes,
|
RaidTimeMinutes: baseEscapeTimeMinutes,
|
||||||
ExitChanges: [],
|
ExitChanges: [],
|
||||||
NewSurviveTimeSeconds: null,
|
NewSurviveTimeSeconds: null,
|
||||||
OriginalSurvivalTimeSeconds: db.globals.config.exp.match_end.survived_seconds_requirement
|
OriginalSurvivalTimeSeconds: db.globals.config.exp.match_end.survived_seconds_requirement,
|
||||||
}
|
};
|
||||||
|
|
||||||
// Pmc raid, send default
|
// Pmc raid, send default
|
||||||
if (request.Side.toLowerCase() === "pmc")
|
if (request.Side.toLowerCase() === "pmc")
|
||||||
@ -124,15 +134,17 @@ export class RaidTimeAdjustmentService
|
|||||||
// Send default
|
// Send default
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the weighted percent to reduce the raid time by
|
// Get the weighted percent to reduce the raid time by
|
||||||
const chosenRaidReductionPercent = Number.parseInt(this.weightedRandomHelper.getWeightedValue<string>(
|
const chosenRaidReductionPercent = Number.parseInt(
|
||||||
mapSettings.reductionPercentWeights,
|
this.weightedRandomHelper.getWeightedValue<string>(mapSettings.reductionPercentWeights),
|
||||||
));
|
);
|
||||||
const raidTimeRemainingPercent = 100 - chosenRaidReductionPercent;
|
const raidTimeRemainingPercent = 100 - chosenRaidReductionPercent;
|
||||||
|
|
||||||
// How many minutes raid will last
|
// How many minutes raid will last
|
||||||
const newRaidTimeMinutes = Math.floor(this.randomUtil.reduceValueByPercent(baseEscapeTimeMinutes, chosenRaidReductionPercent));
|
const newRaidTimeMinutes = Math.floor(
|
||||||
|
this.randomUtil.reduceValueByPercent(baseEscapeTimeMinutes, chosenRaidReductionPercent),
|
||||||
|
);
|
||||||
|
|
||||||
// Time player spawns into the raid if it was online
|
// Time player spawns into the raid if it was online
|
||||||
const simulatedRaidStartTimeMinutes = baseEscapeTimeMinutes - newRaidTimeMinutes;
|
const simulatedRaidStartTimeMinutes = baseEscapeTimeMinutes - newRaidTimeMinutes;
|
||||||
@ -140,21 +152,25 @@ export class RaidTimeAdjustmentService
|
|||||||
if (mapSettings.reduceLootByPercent)
|
if (mapSettings.reduceLootByPercent)
|
||||||
{
|
{
|
||||||
// Store time reduction percent in app context so loot gen can pick it up later
|
// Store time reduction percent in app context so loot gen can pick it up later
|
||||||
this.applicationContext.addValue(ContextVariableType.RAID_ADJUSTMENTS,
|
this.applicationContext.addValue(ContextVariableType.RAID_ADJUSTMENTS, {
|
||||||
{
|
dynamicLootPercent: Math.max(raidTimeRemainingPercent, mapSettings.minDynamicLootPercent),
|
||||||
dynamicLootPercent: Math.max(raidTimeRemainingPercent, mapSettings.minDynamicLootPercent),
|
staticLootPercent: Math.max(raidTimeRemainingPercent, mapSettings.minStaticLootPercent),
|
||||||
staticLootPercent: Math.max(raidTimeRemainingPercent, mapSettings.minStaticLootPercent),
|
simulatedRaidStartSeconds: simulatedRaidStartTimeMinutes * 60,
|
||||||
simulatedRaidStartSeconds: simulatedRaidStartTimeMinutes * 60
|
});
|
||||||
});
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Update result object with new time
|
// Update result object with new time
|
||||||
result.RaidTimeMinutes = newRaidTimeMinutes;
|
result.RaidTimeMinutes = newRaidTimeMinutes;
|
||||||
|
|
||||||
this.logger.debug(`Reduced: ${request.Location} raid time by: ${chosenRaidReductionPercent}% to ${newRaidTimeMinutes} minutes`)
|
this.logger.debug(
|
||||||
|
`Reduced: ${request.Location} raid time by: ${chosenRaidReductionPercent}% to ${newRaidTimeMinutes} minutes`,
|
||||||
|
);
|
||||||
|
|
||||||
// Calculate how long player needs to be in raid to get a `survived` extract status
|
// Calculate how long player needs to be in raid to get a `survived` extract status
|
||||||
result.NewSurviveTimeSeconds = Math.max(result.OriginalSurvivalTimeSeconds - ((baseEscapeTimeMinutes - newRaidTimeMinutes) * 60), 0);
|
result.NewSurviveTimeSeconds = Math.max(
|
||||||
|
result.OriginalSurvivalTimeSeconds - ((baseEscapeTimeMinutes - newRaidTimeMinutes) * 60),
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
|
||||||
const exitAdjustments = this.getExitAdjustments(mapBase, newRaidTimeMinutes);
|
const exitAdjustments = this.getExitAdjustments(mapBase, newRaidTimeMinutes);
|
||||||
if (exitAdjustments)
|
if (exitAdjustments)
|
||||||
@ -188,74 +204,73 @@ export class RaidTimeAdjustmentService
|
|||||||
* @param newRaidTimeMinutes How long raid is in minutes
|
* @param newRaidTimeMinutes How long raid is in minutes
|
||||||
* @returns List of exit changes to send to client
|
* @returns List of exit changes to send to client
|
||||||
*/
|
*/
|
||||||
protected getExitAdjustments(mapBase: ILocationBase, newRaidTimeMinutes: number): ExtractChange[]
|
protected getExitAdjustments(mapBase: ILocationBase, newRaidTimeMinutes: number): ExtractChange[]
|
||||||
|
{
|
||||||
|
const result = [];
|
||||||
|
// Adjust train exits only
|
||||||
|
for (const exit of mapBase.exits)
|
||||||
{
|
{
|
||||||
const result = [];
|
if (exit.PassageRequirement !== "Train")
|
||||||
// Adjust train exits only
|
|
||||||
for (const exit of mapBase.exits)
|
|
||||||
{
|
{
|
||||||
if (exit.PassageRequirement !== "Train")
|
continue;
|
||||||
{
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Prepare train adjustment object
|
|
||||||
const exitChange: ExtractChange = {
|
|
||||||
Name: exit.Name,
|
|
||||||
MinTime: null,
|
|
||||||
MaxTime: null,
|
|
||||||
Chance: null
|
|
||||||
}
|
|
||||||
|
|
||||||
// At what minute we simulate the player joining the raid
|
|
||||||
const simulatedRaidEntryTimeMinutes = mapBase.EscapeTimeLimit - newRaidTimeMinutes;
|
|
||||||
|
|
||||||
// How many seconds have elapsed in the raid when the player joins
|
|
||||||
const reductionSeconds = simulatedRaidEntryTimeMinutes * 60;
|
|
||||||
|
|
||||||
// Delay between the train extract activating and it becoming available to board
|
|
||||||
//
|
|
||||||
// Test method for determining this value:
|
|
||||||
// 1) Set MinTime, MaxTime, and Count for the train extract all to 120
|
|
||||||
// 2) Load into Reserve or Lighthouse as a PMC (both have the same result)
|
|
||||||
// 3) Board the train when it arrives
|
|
||||||
// 4) Check the raid time on the Raid Ended Screen (it should always be the same)
|
|
||||||
//
|
|
||||||
// trainArrivalDelaySeconds = [raid time on raid-ended screen] - MaxTime - Count - ExfiltrationTime
|
|
||||||
// Example: Raid Time = 5:33 = 333 seconds
|
|
||||||
// trainArrivalDelaySeconds = 333 - 120 - 120 - 5 = 88
|
|
||||||
//
|
|
||||||
// I added 2 seconds just to be safe...
|
|
||||||
//
|
|
||||||
const trainArrivalDelaySeconds = this.locationConfig.scavRaidTimeSettings.settings.trainArrivalDelayObservedSeconds;
|
|
||||||
|
|
||||||
// Determine the earliest possible time in the raid when the train would leave
|
|
||||||
const earliestPossibleDepartureMinutes = (exit.MinTime + exit.Count + exit.ExfiltrationTime + trainArrivalDelaySeconds) / 60;
|
|
||||||
|
|
||||||
// If raid is after last moment train can leave, assume train has already left, disable extract
|
|
||||||
const mostPossibleTimeRemainingAfterDeparture = mapBase.EscapeTimeLimit - earliestPossibleDepartureMinutes;
|
|
||||||
if (newRaidTimeMinutes < mostPossibleTimeRemainingAfterDeparture)
|
|
||||||
{
|
|
||||||
exitChange.Chance = 0;
|
|
||||||
|
|
||||||
this.logger.debug(`Train Exit: ${exit.Name} disabled as new raid time ${newRaidTimeMinutes} minutes is below ${mostPossibleTimeRemainingAfterDeparture} minutes`);
|
|
||||||
|
|
||||||
result.push(exitChange);
|
|
||||||
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Reduce extract arrival times. Negative values seem to make extract turn red in game.
|
|
||||||
exitChange.MinTime = Math.max(exit.MinTime - reductionSeconds, 0);
|
|
||||||
exitChange.MaxTime = Math.max(exit.MaxTime - reductionSeconds, 0);
|
|
||||||
|
|
||||||
this.logger.debug(`Train appears between: ${exitChange.MinTime} and ${exitChange.MaxTime} seconds raid time`);
|
|
||||||
|
|
||||||
result.push(exitChange);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return result.length > 0
|
// Prepare train adjustment object
|
||||||
? result
|
const exitChange: ExtractChange = { Name: exit.Name, MinTime: null, MaxTime: null, Chance: null };
|
||||||
: null ;
|
|
||||||
|
// At what minute we simulate the player joining the raid
|
||||||
|
const simulatedRaidEntryTimeMinutes = mapBase.EscapeTimeLimit - newRaidTimeMinutes;
|
||||||
|
|
||||||
|
// How many seconds have elapsed in the raid when the player joins
|
||||||
|
const reductionSeconds = simulatedRaidEntryTimeMinutes * 60;
|
||||||
|
|
||||||
|
// Delay between the train extract activating and it becoming available to board
|
||||||
|
//
|
||||||
|
// Test method for determining this value:
|
||||||
|
// 1) Set MinTime, MaxTime, and Count for the train extract all to 120
|
||||||
|
// 2) Load into Reserve or Lighthouse as a PMC (both have the same result)
|
||||||
|
// 3) Board the train when it arrives
|
||||||
|
// 4) Check the raid time on the Raid Ended Screen (it should always be the same)
|
||||||
|
//
|
||||||
|
// trainArrivalDelaySeconds = [raid time on raid-ended screen] - MaxTime - Count - ExfiltrationTime
|
||||||
|
// Example: Raid Time = 5:33 = 333 seconds
|
||||||
|
// trainArrivalDelaySeconds = 333 - 120 - 120 - 5 = 88
|
||||||
|
//
|
||||||
|
// I added 2 seconds just to be safe...
|
||||||
|
//
|
||||||
|
const trainArrivalDelaySeconds =
|
||||||
|
this.locationConfig.scavRaidTimeSettings.settings.trainArrivalDelayObservedSeconds;
|
||||||
|
|
||||||
|
// Determine the earliest possible time in the raid when the train would leave
|
||||||
|
const earliestPossibleDepartureMinutes =
|
||||||
|
(exit.MinTime + exit.Count + exit.ExfiltrationTime + trainArrivalDelaySeconds) / 60;
|
||||||
|
|
||||||
|
// If raid is after last moment train can leave, assume train has already left, disable extract
|
||||||
|
const mostPossibleTimeRemainingAfterDeparture = mapBase.EscapeTimeLimit - earliestPossibleDepartureMinutes;
|
||||||
|
if (newRaidTimeMinutes < mostPossibleTimeRemainingAfterDeparture)
|
||||||
|
{
|
||||||
|
exitChange.Chance = 0;
|
||||||
|
|
||||||
|
this.logger.debug(
|
||||||
|
`Train Exit: ${exit.Name} disabled as new raid time ${newRaidTimeMinutes} minutes is below ${mostPossibleTimeRemainingAfterDeparture} minutes`,
|
||||||
|
);
|
||||||
|
|
||||||
|
result.push(exitChange);
|
||||||
|
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Reduce extract arrival times. Negative values seem to make extract turn red in game.
|
||||||
|
exitChange.MinTime = Math.max(exit.MinTime - reductionSeconds, 0);
|
||||||
|
exitChange.MaxTime = Math.max(exit.MaxTime - reductionSeconds, 0);
|
||||||
|
|
||||||
|
this.logger.debug(
|
||||||
|
`Train appears between: ${exitChange.MinTime} and ${exitChange.MaxTime} seconds raid time`,
|
||||||
|
);
|
||||||
|
|
||||||
|
result.push(exitChange);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
return result.length > 0 ? result : null;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
@ -124,7 +124,7 @@ export class RepairService
|
|||||||
const options: IProcessBuyTradeRequestData = {
|
const options: IProcessBuyTradeRequestData = {
|
||||||
scheme_items: [{
|
scheme_items: [{
|
||||||
id: "5449016a4bdc2d6f028b456f", // Rouble tpl
|
id: "5449016a4bdc2d6f028b456f", // Rouble tpl
|
||||||
count: Math.round(repairCost)
|
count: Math.round(repairCost),
|
||||||
}],
|
}],
|
||||||
tid: traderId,
|
tid: traderId,
|
||||||
Action: "SptRepair",
|
Action: "SptRepair",
|
||||||
@ -214,10 +214,7 @@ export class RepairService
|
|||||||
else
|
else
|
||||||
{
|
{
|
||||||
// Trader repair - Not as accurate as kit, needs data from live
|
// Trader repair - Not as accurate as kit, needs data from live
|
||||||
return Math.min(
|
return Math.min(repairDetails.repairAmount / 10, this.repairConfig.maxIntellectGainPerRepair.trader);
|
||||||
repairDetails.repairAmount / 10,
|
|
||||||
this.repairConfig.maxIntellectGainPerRepair.trader,
|
|
||||||
);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -440,7 +437,13 @@ export class RepairService
|
|||||||
|
|
||||||
if (this.shouldBuffItem(repairDetails, pmcData))
|
if (this.shouldBuffItem(repairDetails, pmcData))
|
||||||
{
|
{
|
||||||
if (this.itemHelper.isOfBaseclasses(repairDetails.repairedItem._tpl, [BaseClasses.ARMOR, BaseClasses.VEST, BaseClasses.HEADWEAR]))
|
if (
|
||||||
|
this.itemHelper.isOfBaseclasses(repairDetails.repairedItem._tpl, [
|
||||||
|
BaseClasses.ARMOR,
|
||||||
|
BaseClasses.VEST,
|
||||||
|
BaseClasses.HEADWEAR,
|
||||||
|
])
|
||||||
|
)
|
||||||
{
|
{
|
||||||
const armorConfig = this.repairConfig.repairKit.armor;
|
const armorConfig = this.repairConfig.repairKit.armor;
|
||||||
this.addBuff(armorConfig, repairDetails.repairedItem);
|
this.addBuff(armorConfig, repairDetails.repairedItem);
|
||||||
@ -539,7 +542,13 @@ export class RepairService
|
|||||||
*/
|
*/
|
||||||
protected getItemSkillType(itemTemplate: ITemplateItem): SkillTypes
|
protected getItemSkillType(itemTemplate: ITemplateItem): SkillTypes
|
||||||
{
|
{
|
||||||
if (this.itemHelper.isOfBaseclasses(itemTemplate._id, [BaseClasses.ARMOR, BaseClasses.VEST, BaseClasses.HEADWEAR]))
|
if (
|
||||||
|
this.itemHelper.isOfBaseclasses(itemTemplate._id, [
|
||||||
|
BaseClasses.ARMOR,
|
||||||
|
BaseClasses.VEST,
|
||||||
|
BaseClasses.HEADWEAR,
|
||||||
|
])
|
||||||
|
)
|
||||||
{
|
{
|
||||||
if (itemTemplate._props.ArmorType === "Light")
|
if (itemTemplate._props.ArmorType === "Light")
|
||||||
{
|
{
|
||||||
|
@ -529,7 +529,7 @@ export class SeasonalEventService
|
|||||||
{
|
{
|
||||||
const mapData: ILocationData = maps[gifterMapSettings.map];
|
const mapData: ILocationData = maps[gifterMapSettings.map];
|
||||||
// Dont add gifter to map twice
|
// Dont add gifter to map twice
|
||||||
if (mapData.base.BossLocationSpawn.some(boss => boss.BossName === "gifter"))
|
if (mapData.base.BossLocationSpawn.some((boss) => boss.BossName === "gifter"))
|
||||||
{
|
{
|
||||||
continue;
|
continue;
|
||||||
}
|
}
|
||||||
|
@ -17,4 +17,4 @@ export class TraderServicesService
|
|||||||
const traderServices = this.databaseServer.getTables().traders[traderId]?.services;
|
const traderServices = this.databaseServer.getTables().traders[traderId]?.services;
|
||||||
return traderServices ?? [];
|
return traderServices ?? [];
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -211,7 +211,9 @@ export class CustomItemService
|
|||||||
const weapon = this.itemHelper.getItem(weaponTpl);
|
const weapon = this.itemHelper.getItem(weaponTpl);
|
||||||
if (!weapon[0])
|
if (!weapon[0])
|
||||||
{
|
{
|
||||||
this.logger.warning(`Unable to add custom weapon ${weaponTpl} to PMCs as it cannot be found in the Item db`);
|
this.logger.warning(
|
||||||
|
`Unable to add custom weapon ${weaponTpl} to PMCs as it cannot be found in the Item db`,
|
||||||
|
);
|
||||||
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
@ -84,7 +84,7 @@ export class DatabaseImporter implements OnLoad
|
|||||||
const imageFilePath = `${this.filepath}images/`;
|
const imageFilePath = `${this.filepath}images/`;
|
||||||
const directories = this.vfs.getDirs(imageFilePath);
|
const directories = this.vfs.getDirs(imageFilePath);
|
||||||
this.loadImages(imageFilePath, directories, [
|
this.loadImages(imageFilePath, directories, [
|
||||||
"/files/achievement/",
|
"/files/achievement/",
|
||||||
"/files/CONTENT/banners/",
|
"/files/CONTENT/banners/",
|
||||||
"/files/handbook/",
|
"/files/handbook/",
|
||||||
"/files/Hideout/",
|
"/files/Hideout/",
|
||||||
|
@ -51,4 +51,4 @@ export class HashUtil
|
|||||||
const max = 1999999;
|
const max = 1999999;
|
||||||
return (max > min) ? Math.floor(Math.random() * (max - min + 1) + min) : min;
|
return (max > min) ? Math.floor(Math.random() * (max - min + 1) + min) : min;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -83,11 +83,7 @@ export class HttpResponseUtil
|
|||||||
{
|
{
|
||||||
if (output.warnings?.length > 0)
|
if (output.warnings?.length > 0)
|
||||||
{
|
{
|
||||||
output.warnings.push({
|
output.warnings.push({ index: output.warnings?.length - 1, errmsg: message, code: errorCode.toString() });
|
||||||
index: output.warnings?.length - 1,
|
|
||||||
errmsg: message,
|
|
||||||
code: errorCode.toString()
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
|
@ -200,9 +200,7 @@ export class ProbabilityObject<K, V = undefined>
|
|||||||
@injectable()
|
@injectable()
|
||||||
export class RandomUtil
|
export class RandomUtil
|
||||||
{
|
{
|
||||||
constructor(
|
constructor(@inject("JsonUtil") protected jsonUtil: JsonUtil, @inject("WinstonLogger") protected logger: ILogger)
|
||||||
@inject("JsonUtil") protected jsonUtil: JsonUtil,
|
|
||||||
@inject("WinstonLogger") protected logger: ILogger)
|
|
||||||
{
|
{
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -296,15 +294,15 @@ export class RandomUtil
|
|||||||
v = Math.random();
|
v = Math.random();
|
||||||
}
|
}
|
||||||
const w = Math.sqrt(-2.0 * Math.log(u)) * Math.cos((2.0 * Math.PI) * v);
|
const w = Math.sqrt(-2.0 * Math.log(u)) * Math.cos((2.0 * Math.PI) * v);
|
||||||
const valueDrawn = mean + w * sigma;
|
const valueDrawn = mean + w * sigma;
|
||||||
if (valueDrawn < 0)
|
if (valueDrawn < 0)
|
||||||
{
|
{
|
||||||
if (attempt > 100)
|
if (attempt > 100)
|
||||||
{
|
{
|
||||||
return this.getFloat(0.01, mean * 2);
|
return this.getFloat(0.01, mean * 2);
|
||||||
}
|
}
|
||||||
|
|
||||||
return this.getNormallyDistributedRandomNumber(mean, sigma, attempt++);
|
return this.getNormallyDistributedRandomNumber(mean, sigma, attempt++);
|
||||||
}
|
}
|
||||||
|
|
||||||
return valueDrawn;
|
return valueDrawn;
|
||||||
@ -486,7 +484,7 @@ export class RandomUtil
|
|||||||
|
|
||||||
// Roll a number between 0 and 1
|
// Roll a number between 0 and 1
|
||||||
const rolledChance = this.getInt(0, maxRoll) / 10000;
|
const rolledChance = this.getInt(0, maxRoll) / 10000;
|
||||||
|
|
||||||
return rolledChance <= probabilityChance;
|
return rolledChance <= probabilityChance;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -25,22 +25,19 @@ describe("HealthController", () =>
|
|||||||
{
|
{
|
||||||
it("Should Heal Players heavy bleed and heal chest to full hp", () =>
|
it("Should Heal Players heavy bleed and heal chest to full hp", () =>
|
||||||
{
|
{
|
||||||
const maxHealth = 100
|
const maxHealth = 100;
|
||||||
const pmcData = {
|
const pmcData = {
|
||||||
Health: {
|
Health: {
|
||||||
BodyParts: {
|
BodyParts: {
|
||||||
Chest: {
|
Chest: {
|
||||||
Health: {
|
Health: {
|
||||||
Current: 50, // Has damage
|
Current: 50, // Has damage
|
||||||
Maximum: maxHealth
|
Maximum: maxHealth,
|
||||||
},
|
},
|
||||||
Effects: {HeavyBleeding: {
|
Effects: { HeavyBleeding: { Time: 20 } },
|
||||||
Time: 20
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const bleedRemovalAndLimbHealRequest = {
|
const bleedRemovalAndLimbHealRequest = {
|
||||||
Action: "RestoreHealth",
|
Action: "RestoreHealth",
|
||||||
@ -49,62 +46,53 @@ describe("HealthController", () =>
|
|||||||
BodyParts: {
|
BodyParts: {
|
||||||
Chest: {
|
Chest: {
|
||||||
Health: 23, // > 0 value means it will heal
|
Health: 23, // > 0 value means it will heal
|
||||||
Effects: ["HeavyBleeding"] // non-null means it will remove effect from player
|
Effects: ["HeavyBleeding"], // non-null means it will remove effect from player
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
const sessionId = "12345";
|
const sessionId = "12345";
|
||||||
|
|
||||||
// Mock output generation
|
// Mock output generation
|
||||||
vi.spyOn((healthController as any).eventOutputHolder, "getOutput").mockReturnValue(
|
vi.spyOn((healthController as any).eventOutputHolder, "getOutput").mockReturnValue({
|
||||||
{
|
warnings: {},
|
||||||
warnings: {},
|
profileChanges: { "12345": { health: {} } },
|
||||||
profileChanges: {
|
});
|
||||||
"12345": {
|
|
||||||
health: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mock payment
|
// Mock payment
|
||||||
vi.spyOn((healthController as any).paymentService, "payMoney").mockReturnValue(
|
vi.spyOn((healthController as any).paymentService, "payMoney").mockReturnValue({
|
||||||
{
|
warnings: {},
|
||||||
warnings: {},
|
profileChanges: { "12345": { health: {} } },
|
||||||
profileChanges: {
|
});
|
||||||
"12345": {
|
|
||||||
health: {}
|
const result = healthController.healthTreatment(
|
||||||
}
|
pmcData as unknown as IPmcData,
|
||||||
}
|
bleedRemovalAndLimbHealRequest as IHealthTreatmentRequestData,
|
||||||
});
|
sessionId,
|
||||||
|
);
|
||||||
|
|
||||||
const result = healthController.healthTreatment(pmcData as unknown as IPmcData, bleedRemovalAndLimbHealRequest as IHealthTreatmentRequestData, sessionId);
|
|
||||||
|
|
||||||
// Has healed chest to full
|
// Has healed chest to full
|
||||||
expect(result.profileChanges[sessionId].health.BodyParts.Chest.Health.Current).equals(maxHealth);
|
expect(result.profileChanges[sessionId].health.BodyParts.Chest.Health.Current).equals(maxHealth);
|
||||||
|
|
||||||
// Has removed Heavy bleed effect from chest
|
// Has removed Heavy bleed effect from chest
|
||||||
expect(result.profileChanges[sessionId].health.BodyParts.Chest).not.toHaveProperty("Effects");
|
expect(result.profileChanges[sessionId].health.BodyParts.Chest).not.toHaveProperty("Effects");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should Heal Players heavy bleed and leave limb health at existing value", () =>
|
it("Should Heal Players heavy bleed and leave limb health at existing value", () =>
|
||||||
{
|
{
|
||||||
const maxHealth = 100
|
const maxHealth = 100;
|
||||||
const pmcData = {
|
const pmcData = {
|
||||||
Health: {
|
Health: {
|
||||||
BodyParts: {
|
BodyParts: {
|
||||||
Chest: {
|
Chest: {
|
||||||
Health: {
|
Health: {
|
||||||
Current: 50, // Has damage
|
Current: 50, // Has damage
|
||||||
Maximum: maxHealth
|
Maximum: maxHealth,
|
||||||
},
|
},
|
||||||
Effects: {HeavyBleeding: {
|
Effects: { HeavyBleeding: { Time: 20 } },
|
||||||
Time: 20
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const limbOnlyHealRequest = {
|
const limbOnlyHealRequest = {
|
||||||
Action: "RestoreHealth",
|
Action: "RestoreHealth",
|
||||||
@ -113,47 +101,41 @@ describe("HealthController", () =>
|
|||||||
BodyParts: {
|
BodyParts: {
|
||||||
Chest: {
|
Chest: {
|
||||||
Health: 23, // > 0 value means it will heal limb to full
|
Health: 23, // > 0 value means it will heal limb to full
|
||||||
Effects: null // null means no healing of effects
|
Effects: null, // null means no healing of effects
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
const sessionId = "12345";
|
const sessionId = "12345";
|
||||||
|
|
||||||
// Mock output generation
|
// Mock output generation
|
||||||
vi.spyOn((healthController as any).eventOutputHolder, "getOutput").mockReturnValue(
|
vi.spyOn((healthController as any).eventOutputHolder, "getOutput").mockReturnValue({
|
||||||
{
|
warnings: {},
|
||||||
warnings: {},
|
profileChanges: { "12345": { health: {} } },
|
||||||
profileChanges: {
|
});
|
||||||
"12345": {
|
|
||||||
health: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mock payment
|
// Mock payment
|
||||||
vi.spyOn((healthController as any).paymentService, "payMoney").mockReturnValue(
|
vi.spyOn((healthController as any).paymentService, "payMoney").mockReturnValue({
|
||||||
{
|
warnings: {},
|
||||||
warnings: {},
|
profileChanges: { "12345": { health: {} } },
|
||||||
profileChanges: {
|
});
|
||||||
"12345": {
|
|
||||||
health: {}
|
const result = healthController.healthTreatment(
|
||||||
}
|
pmcData as unknown as IPmcData,
|
||||||
}
|
limbOnlyHealRequest as IHealthTreatmentRequestData,
|
||||||
});
|
sessionId,
|
||||||
|
);
|
||||||
|
|
||||||
const result = healthController.healthTreatment(pmcData as unknown as IPmcData, limbOnlyHealRequest as IHealthTreatmentRequestData, sessionId);
|
|
||||||
|
|
||||||
// Has healed chest to full
|
// Has healed chest to full
|
||||||
expect(result.profileChanges[sessionId].health.BodyParts.Chest.Health.Current).equals(maxHealth);
|
expect(result.profileChanges[sessionId].health.BodyParts.Chest.Health.Current).equals(maxHealth);
|
||||||
|
|
||||||
// Has not removed Heavy bleed effect from chest
|
// Has not removed Heavy bleed effect from chest
|
||||||
expect(result.profileChanges[sessionId].health.BodyParts.Chest).toHaveProperty("Effects");
|
expect(result.profileChanges[sessionId].health.BodyParts.Chest).toHaveProperty("Effects");
|
||||||
});
|
});
|
||||||
|
|
||||||
it("Should Heal Players heavy bleed and leave limb health at existing value", () =>
|
it("Should Heal Players heavy bleed and leave limb health at existing value", () =>
|
||||||
{
|
{
|
||||||
const maxHealth = 100
|
const maxHealth = 100;
|
||||||
const currentHealth = 50;
|
const currentHealth = 50;
|
||||||
const pmcData = {
|
const pmcData = {
|
||||||
Health: {
|
Health: {
|
||||||
@ -161,15 +143,12 @@ describe("HealthController", () =>
|
|||||||
Chest: {
|
Chest: {
|
||||||
Health: {
|
Health: {
|
||||||
Current: currentHealth, // Has damage
|
Current: currentHealth, // Has damage
|
||||||
Maximum: maxHealth
|
Maximum: maxHealth,
|
||||||
},
|
},
|
||||||
Effects: {HeavyBleeding: {
|
Effects: { HeavyBleeding: { Time: 20 } },
|
||||||
Time: 20
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
};
|
||||||
const limbOnlyHealRequest = {
|
const limbOnlyHealRequest = {
|
||||||
Action: "RestoreHealth",
|
Action: "RestoreHealth",
|
||||||
@ -178,40 +157,34 @@ describe("HealthController", () =>
|
|||||||
BodyParts: {
|
BodyParts: {
|
||||||
Chest: {
|
Chest: {
|
||||||
Health: 0, // 0 value means it will not heal and damage
|
Health: 0, // 0 value means it will not heal and damage
|
||||||
Effects: null // null means no healing of effects
|
Effects: null, // null means no healing of effects
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
}
|
},
|
||||||
};
|
};
|
||||||
const sessionId = "12345";
|
const sessionId = "12345";
|
||||||
|
|
||||||
// Mock output generation
|
// Mock output generation
|
||||||
vi.spyOn((healthController as any).eventOutputHolder, "getOutput").mockReturnValue(
|
vi.spyOn((healthController as any).eventOutputHolder, "getOutput").mockReturnValue({
|
||||||
{
|
warnings: {},
|
||||||
warnings: {},
|
profileChanges: { "12345": { health: {} } },
|
||||||
profileChanges: {
|
});
|
||||||
"12345": {
|
|
||||||
health: {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Mock payment
|
// Mock payment
|
||||||
vi.spyOn((healthController as any).paymentService, "payMoney").mockReturnValue(
|
vi.spyOn((healthController as any).paymentService, "payMoney").mockReturnValue({
|
||||||
{
|
warnings: {},
|
||||||
warnings: {},
|
profileChanges: { "12345": { health: {} } },
|
||||||
profileChanges: {
|
});
|
||||||
"12345": {
|
|
||||||
health: {}
|
const result = healthController.healthTreatment(
|
||||||
}
|
pmcData as unknown as IPmcData,
|
||||||
}
|
limbOnlyHealRequest as IHealthTreatmentRequestData,
|
||||||
});
|
sessionId,
|
||||||
|
);
|
||||||
|
|
||||||
const result = healthController.healthTreatment(pmcData as unknown as IPmcData, limbOnlyHealRequest as IHealthTreatmentRequestData, sessionId);
|
|
||||||
|
|
||||||
// Has not healed chest to full
|
// Has not healed chest to full
|
||||||
expect(result.profileChanges[sessionId].health.BodyParts.Chest.Health.Current).equals(currentHealth);
|
expect(result.profileChanges[sessionId].health.BodyParts.Chest.Health.Current).equals(currentHealth);
|
||||||
|
|
||||||
// Has not removed Heavy bleed effect from chest
|
// Has not removed Heavy bleed effect from chest
|
||||||
expect(result.profileChanges[sessionId].health.BodyParts.Chest).toHaveProperty("Effects");
|
expect(result.profileChanges[sessionId].health.BodyParts.Chest).toHaveProperty("Effects");
|
||||||
});
|
});
|
||||||
|
Loading…
x
Reference in New Issue
Block a user