Removed unused code and repurposed save endpoint for scav profile saving
This commit is contained in:
parent
124e23b8f6
commit
4eeedc4257
@ -3,7 +3,7 @@ import { InraidController } from "@spt/controllers/InraidController";
|
||||
import { IEmptyRequestData } from "@spt/models/eft/common/IEmptyRequestData";
|
||||
import { INullResponseData } from "@spt/models/eft/httpResponse/INullResponseData";
|
||||
import { IRegisterPlayerRequestData } from "@spt/models/eft/inRaid/IRegisterPlayerRequestData";
|
||||
import { ISaveProgressRequestData } from "@spt/models/eft/inRaid/ISaveProgressRequestData";
|
||||
import { IScavSaveRequestData } from "@spt/models/eft/inRaid/IScavSaveRequestData";
|
||||
import { HttpResponseUtil } from "@spt/utils/HttpResponseUtil";
|
||||
|
||||
/**
|
||||
@ -39,9 +39,9 @@ export class InraidCallbacks
|
||||
* @param sessionID Session id
|
||||
* @returns Null http response
|
||||
*/
|
||||
public saveProgress(url: string, info: ISaveProgressRequestData, sessionID: string): INullResponseData
|
||||
public saveProgress(url: string, info: IScavSaveRequestData, sessionID: string): INullResponseData
|
||||
{
|
||||
this.inraidController.savePostRaidProgressLegacy(info, sessionID);
|
||||
this.inraidController.savePostRaidProfileForScav(info, sessionID);
|
||||
return this.httpResponse.nullResponse();
|
||||
}
|
||||
|
||||
|
@ -1,41 +1,16 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
import { ApplicationContext } from "@spt/context/ApplicationContext";
|
||||
import { ContextVariableType } from "@spt/context/ContextVariableType";
|
||||
import { PlayerScavGenerator } from "@spt/generators/PlayerScavGenerator";
|
||||
import { HealthHelper } from "@spt/helpers/HealthHelper";
|
||||
import { InRaidHelper } from "@spt/helpers/InRaidHelper";
|
||||
import { ItemHelper } from "@spt/helpers/ItemHelper";
|
||||
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
|
||||
import { QuestHelper } from "@spt/helpers/QuestHelper";
|
||||
import { TraderHelper } from "@spt/helpers/TraderHelper";
|
||||
import { ILocationBase } from "@spt/models/eft/common/ILocationBase";
|
||||
import { IPmcData } from "@spt/models/eft/common/IPmcData";
|
||||
import { BodyPartHealth } from "@spt/models/eft/common/tables/IBotBase";
|
||||
import { IRegisterPlayerRequestData } from "@spt/models/eft/inRaid/IRegisterPlayerRequestData";
|
||||
import { ISaveProgressRequestData } from "@spt/models/eft/inRaid/ISaveProgressRequestData";
|
||||
import { IScavSaveRequestData } from "@spt/models/eft/inRaid/IScavSaveRequestData";
|
||||
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
||||
import { ItemTpl } from "@spt/models/enums/ItemTpl";
|
||||
import { PlayerRaidEndState } from "@spt/models/enums/PlayerRaidEndState";
|
||||
import { QuestStatus } from "@spt/models/enums/QuestStatus";
|
||||
import { SkillTypes } from "@spt/models/enums/SkillTypes";
|
||||
import { Traders } from "@spt/models/enums/Traders";
|
||||
import { IBotConfig } from "@spt/models/spt/config/IBotConfig";
|
||||
import { IHideoutConfig } from "@spt/models/spt/config/IHideoutConfig";
|
||||
import { IInRaidConfig } from "@spt/models/spt/config/IInRaidConfig";
|
||||
import { ILocationConfig } from "@spt/models/spt/config/ILocationConfig";
|
||||
import { IRagfairConfig } from "@spt/models/spt/config/IRagfairConfig";
|
||||
import { ITraderConfig } from "@spt/models/spt/config/ITraderConfig";
|
||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||
import { SaveServer } from "@spt/servers/SaveServer";
|
||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||
import { InsuranceService } from "@spt/services/InsuranceService";
|
||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
||||
import { MailSendService } from "@spt/services/MailSendService";
|
||||
import { MatchBotDetailsCacheService } from "@spt/services/MatchBotDetailsCacheService";
|
||||
import { PmcChatResponseService } from "@spt/services/PmcChatResponseService";
|
||||
import { RandomUtil } from "@spt/utils/RandomUtil";
|
||||
import { TimeUtil } from "@spt/utils/TimeUtil";
|
||||
|
||||
/**
|
||||
* Logic for handling In Raid callbacks
|
||||
@ -44,39 +19,18 @@ import { TimeUtil } from "@spt/utils/TimeUtil";
|
||||
export class InraidController
|
||||
{
|
||||
protected inRaidConfig: IInRaidConfig;
|
||||
protected traderConfig: ITraderConfig;
|
||||
protected locationConfig: ILocationConfig;
|
||||
protected ragfairConfig: IRagfairConfig;
|
||||
protected hideoutConfig: IHideoutConfig;
|
||||
protected botConfig: IBotConfig;
|
||||
|
||||
constructor(
|
||||
@inject("PrimaryLogger") protected logger: ILogger,
|
||||
@inject("SaveServer") protected saveServer: SaveServer,
|
||||
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||
@inject("DatabaseService") protected databaseService: DatabaseService,
|
||||
@inject("PmcChatResponseService") protected pmcChatResponseService: PmcChatResponseService,
|
||||
@inject("MatchBotDetailsCacheService") protected matchBotDetailsCacheService: MatchBotDetailsCacheService,
|
||||
@inject("QuestHelper") protected questHelper: QuestHelper,
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||
@inject("PlayerScavGenerator") protected playerScavGenerator: PlayerScavGenerator,
|
||||
@inject("HealthHelper") protected healthHelper: HealthHelper,
|
||||
@inject("TraderHelper") protected traderHelper: TraderHelper,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("InsuranceService") protected insuranceService: InsuranceService,
|
||||
@inject("InRaidHelper") protected inRaidHelper: InRaidHelper,
|
||||
@inject("ApplicationContext") protected applicationContext: ApplicationContext,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@inject("MailSendService") protected mailSendService: MailSendService,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
)
|
||||
{
|
||||
this.inRaidConfig = this.configServer.getConfig(ConfigTypes.IN_RAID);
|
||||
this.traderConfig = this.configServer.getConfig(ConfigTypes.TRADER);
|
||||
this.locationConfig = this.configServer.getConfig(ConfigTypes.LOCATION);
|
||||
this.ragfairConfig = this.configServer.getConfig(ConfigTypes.RAGFAIR);
|
||||
this.hideoutConfig = this.configServer.getConfig(ConfigTypes.HIDEOUT);
|
||||
this.botConfig = this.configServer.getConfig(ConfigTypes.BOT);
|
||||
}
|
||||
|
||||
@ -112,507 +66,11 @@ export class InraidController
|
||||
* @param offraidData post-raid request data
|
||||
* @param sessionID Session id
|
||||
*/
|
||||
public savePostRaidProgressLegacy(offraidData: ISaveProgressRequestData, sessionID: string): void
|
||||
public savePostRaidProfileForScav(offraidData: IScavSaveRequestData, sessionID: string): void
|
||||
{
|
||||
this.logger.debug(`Raid outcome: ${offraidData.exit}`);
|
||||
|
||||
if (!this.inRaidConfig.save.loot)
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
if (offraidData.isPlayerScav)
|
||||
{
|
||||
this.savePlayerScavProgress(sessionID, offraidData);
|
||||
}
|
||||
else
|
||||
{
|
||||
this.savePmcProgress(sessionID, offraidData);
|
||||
}
|
||||
|
||||
// Set flea interval time to out-of-raid value
|
||||
this.ragfairConfig.runIntervalSeconds = this.ragfairConfig.runIntervalValues.outOfRaid;
|
||||
this.hideoutConfig.runIntervalSeconds = this.hideoutConfig.runIntervalValues.outOfRaid;
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle updating player profile post-pmc raid
|
||||
* @param sessionID Session id
|
||||
* @param postRaidRequest Post-raid data
|
||||
*/
|
||||
protected savePmcProgress(sessionID: string, postRaidRequest: ISaveProgressRequestData): void
|
||||
{
|
||||
const serverProfile = this.saveServer.getProfile(sessionID);
|
||||
|
||||
const locationName = serverProfile.inraid.location.toLowerCase();
|
||||
|
||||
const map: ILocationBase = this.databaseService.getLocation(locationName).base;
|
||||
|
||||
const serverPmcProfile = serverProfile.characters.pmc;
|
||||
const serverScavProfile = serverProfile.characters.scav;
|
||||
|
||||
const isDead = true;// this.isPlayerDead(postRaidRequest.exit);
|
||||
const preRaidGear = this.inRaidHelper.getPlayerGear(serverPmcProfile.Inventory.items);
|
||||
|
||||
serverProfile.inraid.character = "pmc";
|
||||
|
||||
this.inRaidHelper.updateProfileBaseStats(serverPmcProfile, postRaidRequest, sessionID);
|
||||
this.inRaidHelper.updatePmcProfileDataPostRaid(serverPmcProfile, postRaidRequest, sessionID);
|
||||
|
||||
this.mergePmcAndScavEncyclopedias(serverPmcProfile, serverScavProfile);
|
||||
|
||||
// Check for exit status
|
||||
this.markOrRemoveFoundInRaidItems(postRaidRequest);
|
||||
|
||||
postRaidRequest.profile.Inventory.items = this.itemHelper.replaceIDs(
|
||||
postRaidRequest.profile.Inventory.items,
|
||||
postRaidRequest.profile,
|
||||
serverPmcProfile.InsuredItems,
|
||||
postRaidRequest.profile.Inventory.fastPanel,
|
||||
);
|
||||
this.inRaidHelper.addStackCountToMoneyFromRaid(postRaidRequest.profile.Inventory.items);
|
||||
|
||||
// Purge profile of equipment/container items
|
||||
this.inRaidHelper.setInventory(sessionID, serverPmcProfile, postRaidRequest.profile);
|
||||
|
||||
this.healthHelper.saveVitality(serverPmcProfile, postRaidRequest.health, sessionID);
|
||||
|
||||
// Get array of insured items+child that were lost in raid
|
||||
const gearToStore = this.insuranceService.getGearLostInRaid(
|
||||
serverPmcProfile,
|
||||
postRaidRequest,
|
||||
preRaidGear,
|
||||
sessionID,
|
||||
isDead,
|
||||
);
|
||||
|
||||
if (gearToStore.length > 0)
|
||||
{
|
||||
this.insuranceService.storeGearLostInRaidToSendLater(sessionID, gearToStore);
|
||||
}
|
||||
|
||||
// Edge case - Handle usec players leaving lighthouse with Rogues angry at them
|
||||
if (locationName === "lighthouse" && postRaidRequest.profile.Info.Side.toLowerCase() === "usec")
|
||||
{
|
||||
// Decrement counter if it exists, don't go below 0
|
||||
const remainingCounter = serverPmcProfile?.Stats.Eft.OverallCounters.Items.find((x) =>
|
||||
x.Key.includes("UsecRaidRemainKills"),
|
||||
);
|
||||
if (remainingCounter?.Value > 0)
|
||||
{
|
||||
remainingCounter.Value--;
|
||||
}
|
||||
}
|
||||
|
||||
if (isDead)
|
||||
{
|
||||
this.pmcChatResponseService.sendKillerResponse(
|
||||
sessionID,
|
||||
serverPmcProfile,
|
||||
postRaidRequest.profile.Stats.Eft.Aggressor,
|
||||
);
|
||||
this.matchBotDetailsCacheService.clearCache();
|
||||
|
||||
this.performPostRaidActionsWhenDead(postRaidRequest, serverPmcProfile, sessionID);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Not dead
|
||||
|
||||
// Check for cultist amulets in special slot (only slot it can fit)
|
||||
const sacredAmulet = this.itemHelper.getItemFromPoolByTpl(
|
||||
serverPmcProfile.Inventory.items,
|
||||
ItemTpl.CULTISTAMULET_SACRED_AMULET,
|
||||
"SpecialSlot");
|
||||
if (sacredAmulet)
|
||||
{
|
||||
// No charges left, delete it
|
||||
if (sacredAmulet.upd.CultistAmulet.NumberOfUsages <= 0)
|
||||
{
|
||||
serverPmcProfile.Inventory.items.splice(
|
||||
serverPmcProfile.Inventory.items.indexOf(sacredAmulet),
|
||||
1,
|
||||
);
|
||||
}
|
||||
else if (sacredAmulet.upd.CultistAmulet.NumberOfUsages > 0)
|
||||
{
|
||||
// Charges left, reduce by 1
|
||||
sacredAmulet.upd.CultistAmulet.NumberOfUsages--;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
const victims = postRaidRequest.profile.Stats.Eft.Victims.filter((victim) =>
|
||||
["pmcbear", "pmcusec"].includes(victim.Role.toLowerCase()),
|
||||
);
|
||||
if (victims?.length > 0)
|
||||
{
|
||||
this.pmcChatResponseService.sendVictimResponse(sessionID, victims, serverPmcProfile);
|
||||
}
|
||||
|
||||
this.insuranceService.sendInsuredItems(serverPmcProfile, sessionID, map.Id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Make changes to PMC profile after they've died in raid,
|
||||
* Alter body part hp, handle insurance, delete inventory items, remove carried quest items
|
||||
* @param postRaidSaveRequest Post-raid save request
|
||||
* @param pmcData Pmc profile
|
||||
* @param sessionID Session id
|
||||
* @returns Updated profile object
|
||||
*/
|
||||
protected performPostRaidActionsWhenDead(
|
||||
postRaidSaveRequest: ISaveProgressRequestData,
|
||||
pmcData: IPmcData,
|
||||
sessionID: string,
|
||||
): IPmcData
|
||||
{
|
||||
this.updatePmcHealthPostRaid(postRaidSaveRequest, pmcData);
|
||||
this.inRaidHelper.deleteInventory(pmcData, sessionID);
|
||||
|
||||
if (this.inRaidHelper.shouldQuestItemsBeRemovedOnDeath())
|
||||
{
|
||||
// Find and remove the completed condition from profile if player died, otherwise quest is stuck in limbo
|
||||
// and quest items cannot be picked up again
|
||||
const allQuests = this.questHelper.getQuestsFromDb();
|
||||
const activeQuestIdsInProfile = pmcData.Quests.filter(
|
||||
(profileQuest) =>
|
||||
![QuestStatus.AvailableForStart, QuestStatus.Success, QuestStatus.Expired].includes(
|
||||
profileQuest.status,
|
||||
),
|
||||
).map((x) => x.qid);
|
||||
for (const questItem of postRaidSaveRequest.profile.Stats.Eft.CarriedQuestItems)
|
||||
{
|
||||
// Get quest/find condition for carried quest item
|
||||
const questAndFindItemConditionId = this.questHelper.getFindItemConditionByQuestItem(
|
||||
questItem,
|
||||
activeQuestIdsInProfile,
|
||||
allQuests,
|
||||
);
|
||||
if (Object.keys(questAndFindItemConditionId)?.length > 0)
|
||||
{
|
||||
this.profileHelper.removeQuestConditionFromProfile(pmcData, questAndFindItemConditionId);
|
||||
}
|
||||
}
|
||||
|
||||
// Empty out stored quest items from player inventory
|
||||
pmcData.Stats.Eft.CarriedQuestItems = [];
|
||||
}
|
||||
|
||||
return pmcData;
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust player characters body part hp post-raid
|
||||
* @param postRaidSaveRequest post raid data
|
||||
* @param pmcData player profile
|
||||
*/
|
||||
protected updatePmcHealthPostRaid(postRaidSaveRequest: ISaveProgressRequestData, pmcData: IPmcData): void
|
||||
{
|
||||
switch (postRaidSaveRequest.exit)
|
||||
{
|
||||
case PlayerRaidEndState.LEFT.toString():
|
||||
// Naughty pmc left the raid early!
|
||||
this.reducePmcHealthToPercent(pmcData, 0.01); // 1%
|
||||
break;
|
||||
case PlayerRaidEndState.MISSING_IN_ACTION.toString():
|
||||
// Didn't reach exit in time
|
||||
this.reducePmcHealthToPercent(pmcData, 0.3); // 30%
|
||||
break;
|
||||
default:
|
||||
// Left raid properly, don't make any adjustments
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reduce body part hp to % of max
|
||||
* @param pmcData profile to edit
|
||||
* @param multiplier multiplier to apply to max health
|
||||
*/
|
||||
protected reducePmcHealthToPercent(pmcData: IPmcData, multiplier: number): void
|
||||
{
|
||||
for (const bodyPart of Object.values(pmcData.Health.BodyParts))
|
||||
{
|
||||
(<BodyPartHealth>bodyPart).Health.Current = (<BodyPartHealth>bodyPart).Health.Maximum * multiplier;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle updating the profile post-pscav raid
|
||||
* @param sessionID Session id
|
||||
* @param postRaidRequest Post-raid data of raid
|
||||
*/
|
||||
protected savePlayerScavProgress(sessionID: string, postRaidRequest: ISaveProgressRequestData): void
|
||||
{
|
||||
const serverPmcProfile = this.profileHelper.getPmcProfile(sessionID);
|
||||
const serverScavProfile = this.profileHelper.getScavProfile(sessionID);
|
||||
const isDead = true;// this.isPlayerDead(postRaidRequest.exit);
|
||||
const preRaidScavCharismaProgress = this.profileHelper.getSkillFromProfile(
|
||||
serverScavProfile,
|
||||
SkillTypes.CHARISMA,
|
||||
)?.Progress;
|
||||
|
||||
this.saveServer.getProfile(sessionID).inraid.character = "scav";
|
||||
|
||||
this.inRaidHelper.updateProfileBaseStats(serverScavProfile, postRaidRequest, sessionID);
|
||||
this.inRaidHelper.updateScavProfileDataPostRaid(serverScavProfile, postRaidRequest, sessionID);
|
||||
|
||||
this.mergePmcAndScavEncyclopedias(serverScavProfile, serverPmcProfile);
|
||||
|
||||
this.updatePmcCharismaSkillPostScavRaid(serverScavProfile, serverPmcProfile, preRaidScavCharismaProgress);
|
||||
|
||||
// Completing scav quests create ConditionCounters, these values need to be transported to the PMC profile
|
||||
if (this.profileHasConditionCounters(serverScavProfile))
|
||||
{
|
||||
// Scav quest progress needs to be moved to pmc so player can see it in menu / hand them in
|
||||
this.migrateScavQuestProgressToPmcProfile(serverScavProfile, serverPmcProfile);
|
||||
}
|
||||
|
||||
// Change loot FiR status based on exit status
|
||||
this.markOrRemoveFoundInRaidItems(postRaidRequest);
|
||||
|
||||
postRaidRequest.profile.Inventory.items = this.itemHelper.replaceIDs(
|
||||
postRaidRequest.profile.Inventory.items,
|
||||
postRaidRequest.profile,
|
||||
serverPmcProfile.InsuredItems,
|
||||
postRaidRequest.profile.Inventory.fastPanel,
|
||||
);
|
||||
|
||||
// Some items from client profile don't have upd objects when they're single stack items
|
||||
this.inRaidHelper.addStackCountToMoneyFromRaid(postRaidRequest.profile.Inventory.items);
|
||||
|
||||
// Reset hp/regenerate loot
|
||||
this.handlePostRaidPlayerScavProcess(serverScavProfile, sessionID, postRaidRequest, serverPmcProfile, isDead);
|
||||
}
|
||||
|
||||
/**
|
||||
* merge two dictionaries together
|
||||
* Prioritise pair that has true as a value
|
||||
* @param primary main dictionary
|
||||
* @param secondary Secondary dictionary
|
||||
*/
|
||||
protected mergePmcAndScavEncyclopedias(primary: IPmcData, secondary: IPmcData): void
|
||||
{
|
||||
function extend(target: { [key: string]: boolean }, source: Record<string, boolean>)
|
||||
{
|
||||
for (const key in source)
|
||||
{
|
||||
if (Object.hasOwn(source, key))
|
||||
{
|
||||
target[key] = source[key];
|
||||
}
|
||||
}
|
||||
return target;
|
||||
}
|
||||
|
||||
const merged = extend(extend({}, primary.Encyclopedia), secondary.Encyclopedia);
|
||||
primary.Encyclopedia = merged;
|
||||
secondary.Encyclopedia = merged;
|
||||
}
|
||||
|
||||
/**
|
||||
* Post-scav-raid any charisma increase must be propigated into PMC profile
|
||||
* @param postRaidServerScavProfile Scav profile after adjustments made from raid
|
||||
* @param postRaidServerPmcProfile Pmc profile after raid
|
||||
* @param preRaidScavCharismaProgress charisma progress value pre-raid
|
||||
*/
|
||||
protected updatePmcCharismaSkillPostScavRaid(
|
||||
postRaidServerScavProfile: IPmcData,
|
||||
postRaidServerPmcProfile: IPmcData,
|
||||
preRaidScavCharismaProgress: number,
|
||||
): void
|
||||
{
|
||||
const postRaidScavCharismaSkill = this.profileHelper.getSkillFromProfile(
|
||||
postRaidServerScavProfile,
|
||||
SkillTypes.CHARISMA,
|
||||
);
|
||||
const pmcCharismaSkill = this.profileHelper.getSkillFromProfile(postRaidServerPmcProfile, SkillTypes.CHARISMA);
|
||||
const postRaidScavCharismaGain = postRaidScavCharismaSkill?.Progress - preRaidScavCharismaProgress ?? 0;
|
||||
|
||||
// Scav gained charisma, add to pmc
|
||||
if (postRaidScavCharismaGain > 0)
|
||||
{
|
||||
this.logger.debug(`Applying ${postRaidScavCharismaGain} Charisma skill gained in scav raid to PMC profile`);
|
||||
pmcCharismaSkill.Progress += postRaidScavCharismaGain;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Does provided profile contain any condition counters
|
||||
* @param profile Profile to check for condition counters
|
||||
* @returns Profile has condition counters
|
||||
*/
|
||||
protected profileHasConditionCounters(profile: IPmcData): boolean
|
||||
{
|
||||
if (!profile.TaskConditionCounters)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
return Object.keys(profile.TaskConditionCounters).length > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Scav quest progress isnt transferred automatically from scav to pmc, we do this manually
|
||||
* @param scavProfile Scav profile with quest progress post-raid
|
||||
* @param pmcProfile Server pmc profile to copy scav quest progress into
|
||||
*/
|
||||
protected migrateScavQuestProgressToPmcProfile(scavProfile: IPmcData, pmcProfile: IPmcData): void
|
||||
{
|
||||
const achievements = this.databaseService.getAchievements();
|
||||
|
||||
for (const quest of scavProfile.Quests)
|
||||
{
|
||||
const pmcQuest = pmcProfile.Quests.find((x) => x.qid === quest.qid);
|
||||
if (!pmcQuest)
|
||||
{
|
||||
this.logger.warning(this.localisationService.getText("inraid-unable_to_migrate_pmc_quest_not_found_in_profile", quest.qid));
|
||||
continue;
|
||||
}
|
||||
|
||||
// Status values mismatch or statusTimers counts mismatch
|
||||
if (
|
||||
quest.status !== pmcQuest.status
|
||||
|| Object.keys(quest.statusTimers).length !== Object.keys(pmcQuest.statusTimers).length
|
||||
)
|
||||
{
|
||||
this.logger.debug(
|
||||
`Quest: ${quest.qid} found in PMC profile has different status/statustimer. Scav: ${quest.status} vs PMC: ${pmcQuest.status}`,
|
||||
);
|
||||
pmcQuest.status = quest.status;
|
||||
|
||||
// Copy status timers over + fix bad enum key for each
|
||||
pmcQuest.statusTimers = quest.statusTimers;
|
||||
for (const statusTimerKey in quest.statusTimers)
|
||||
{
|
||||
if (Number.isNaN(Number.parseInt(statusTimerKey)))
|
||||
{
|
||||
quest.statusTimers[QuestStatus[statusTimerKey]] = quest.statusTimers[statusTimerKey];
|
||||
delete quest.statusTimers[statusTimerKey];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Loop over all scav counters and add into pmc profile
|
||||
for (const scavCounter of Object.values(scavProfile.TaskConditionCounters))
|
||||
{
|
||||
// If this is an achievement that isn't for the scav, don't process it
|
||||
const achievement = achievements.find((achievement) => achievement.id === scavCounter.sourceId);
|
||||
if (achievement && achievement.side !== "Savage")
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
this.logger.debug(
|
||||
`Processing counter: ${scavCounter.id} value: ${scavCounter.value} quest: ${scavCounter.sourceId}`,
|
||||
);
|
||||
const counterInPmcProfile = pmcProfile.TaskConditionCounters[scavCounter.id];
|
||||
if (!counterInPmcProfile)
|
||||
{
|
||||
// Doesn't exist yet, push it straight in
|
||||
pmcProfile.TaskConditionCounters[scavCounter.id] = scavCounter;
|
||||
continue;
|
||||
}
|
||||
|
||||
this.logger.debug(
|
||||
`Counter id: ${scavCounter.id} already exists in pmc profile! with value: ${counterInPmcProfile.value} for quest: ${counterInPmcProfile.id}`,
|
||||
);
|
||||
|
||||
// Only adjust counter value if its changed
|
||||
if (counterInPmcProfile.value !== scavCounter.value)
|
||||
{
|
||||
this.logger.debug(`OVERWRITING with values: ${scavCounter.value} quest: ${scavCounter.sourceId}`);
|
||||
counterInPmcProfile.value = scavCounter.value;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Mark inventory items as FiR if player survived raid, otherwise remove FiR from them
|
||||
* @param offraidData Save Progress Request
|
||||
*/
|
||||
protected markOrRemoveFoundInRaidItems(offraidData: ISaveProgressRequestData): void
|
||||
{
|
||||
if (offraidData.exit !== PlayerRaidEndState.SURVIVED)
|
||||
{
|
||||
// Remove FIR status if the player hasn't survived
|
||||
offraidData.profile = this.inRaidHelper.removeSpawnedInSessionPropertyFromItems(offraidData.profile);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update profile after player completes scav raid
|
||||
* @param scavData Scav profile
|
||||
* @param sessionID Session id
|
||||
* @param offraidData Post-raid save request
|
||||
* @param pmcData Pmc profile
|
||||
* @param isDead Is player dead
|
||||
*/
|
||||
protected handlePostRaidPlayerScavProcess(
|
||||
scavData: IPmcData,
|
||||
sessionID: string,
|
||||
offraidData: ISaveProgressRequestData,
|
||||
pmcData: IPmcData,
|
||||
isDead: boolean,
|
||||
): void
|
||||
{
|
||||
// Update scav profile inventory
|
||||
this.inRaidHelper.setInventory(sessionID, scavData, offraidData.profile);
|
||||
|
||||
// Reset scav hp and save to json
|
||||
this.healthHelper.resetVitality(sessionID);
|
||||
this.saveServer.getProfile(sessionID).characters.scav = scavData;
|
||||
|
||||
// Scav karma
|
||||
this.handlePostRaidPlayerScavKarmaChanges(pmcData, offraidData, scavData);
|
||||
|
||||
// Scav died, regen scav loadout and set timer
|
||||
if (isDead)
|
||||
{
|
||||
this.playerScavGenerator.generate(sessionID);
|
||||
}
|
||||
|
||||
// Update last played property
|
||||
pmcData.Info.LastTimePlayedAsSavage = this.timeUtil.getTimestamp();
|
||||
|
||||
this.saveServer.saveProfile(sessionID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update profile with scav karma values based on in-raid actions
|
||||
* @param pmcData Pmc profile
|
||||
* @param offraidData Post-raid save request
|
||||
* @param scavData Scav profile
|
||||
*/
|
||||
protected handlePostRaidPlayerScavKarmaChanges(
|
||||
pmcData: IPmcData,
|
||||
offraidData: ISaveProgressRequestData,
|
||||
scavData: IPmcData,
|
||||
): void
|
||||
{
|
||||
const fenceId = Traders.FENCE;
|
||||
|
||||
let fenceStanding = Number(offraidData.profile.TradersInfo[fenceId].standing);
|
||||
|
||||
// Client doesn't calcualte car extract rep changes, must be done manually
|
||||
// Successful extracts give rep
|
||||
if (offraidData.exit === PlayerRaidEndState.SURVIVED)
|
||||
{
|
||||
fenceStanding += this.inRaidConfig.scavExtractGain;
|
||||
}
|
||||
|
||||
// Make standing changes to pmc profile
|
||||
pmcData.TradersInfo[fenceId].standing = Math.min(Math.max(fenceStanding, -7), 15); // Ensure it stays between -7 and 15
|
||||
this.logger.debug(`New fence standing: ${pmcData.TradersInfo[fenceId].standing}`);
|
||||
|
||||
this.traderHelper.lvlUp(fenceId, pmcData);
|
||||
pmcData.TradersInfo[fenceId].loyaltyLevel = Math.max(pmcData.TradersInfo[fenceId].loyaltyLevel, 1);
|
||||
|
||||
// Copy updated fence rep values into scav profile to ensure consistency
|
||||
scavData.TradersInfo[fenceId].standing = pmcData.TradersInfo[fenceId].standing;
|
||||
scavData.TradersInfo[fenceId].loyaltyLevel = pmcData.TradersInfo[fenceId].loyaltyLevel;
|
||||
serverScavProfile.Inventory.items = offraidData.profile.Inventory.items;
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,118 +1,26 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
import { InventoryHelper } from "@spt/helpers/InventoryHelper";
|
||||
import { ItemHelper } from "@spt/helpers/ItemHelper";
|
||||
import { PaymentHelper } from "@spt/helpers/PaymentHelper";
|
||||
import { ProfileHelper } from "@spt/helpers/ProfileHelper";
|
||||
import { QuestHelper } from "@spt/helpers/QuestHelper";
|
||||
import { IPmcData, IPostRaidPmcData } from "@spt/models/eft/common/IPmcData";
|
||||
import { IQuestStatus, TraderInfo } from "@spt/models/eft/common/tables/IBotBase";
|
||||
import { IPmcData } from "@spt/models/eft/common/IPmcData";
|
||||
import { Item } from "@spt/models/eft/common/tables/IItem";
|
||||
import { ISaveProgressRequestData } from "@spt/models/eft/inRaid/ISaveProgressRequestData";
|
||||
import { IFailQuestRequestData } from "@spt/models/eft/quests/IFailQuestRequestData";
|
||||
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
||||
import { QuestStatus } from "@spt/models/enums/QuestStatus";
|
||||
import { Traders } from "@spt/models/enums/Traders";
|
||||
import { IInRaidConfig } from "@spt/models/spt/config/IInRaidConfig";
|
||||
import { ILostOnDeathConfig } from "@spt/models/spt/config/ILostOnDeathConfig";
|
||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||
import { SaveServer } from "@spt/servers/SaveServer";
|
||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
||||
import { ProfileFixerService } from "@spt/services/ProfileFixerService";
|
||||
import { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
import { RandomUtil } from "@spt/utils/RandomUtil";
|
||||
import { TimeUtil } from "@spt/utils/TimeUtil";
|
||||
|
||||
@injectable()
|
||||
export class InRaidHelper
|
||||
{
|
||||
protected lostOnDeathConfig: ILostOnDeathConfig;
|
||||
protected inRaidConfig: IInRaidConfig;
|
||||
|
||||
constructor(
|
||||
@inject("PrimaryLogger") protected logger: ILogger,
|
||||
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||
@inject("SaveServer") protected saveServer: SaveServer,
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
@inject("DatabaseService") protected databaseService: DatabaseService,
|
||||
@inject("InventoryHelper") protected inventoryHelper: InventoryHelper,
|
||||
@inject("ProfileHelper") protected profileHelper: ProfileHelper,
|
||||
@inject("QuestHelper") protected questHelper: QuestHelper,
|
||||
@inject("PaymentHelper") protected paymentHelper: PaymentHelper,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("ProfileFixerService") protected profileFixerService: ProfileFixerService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@inject("PrimaryCloner") protected cloner: ICloner,
|
||||
)
|
||||
{
|
||||
this.lostOnDeathConfig = this.configServer.getConfig(ConfigTypes.LOST_ON_DEATH);
|
||||
this.inRaidConfig = this.configServer.getConfig(ConfigTypes.IN_RAID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Lookup quest item loss from lostOnDeath config
|
||||
* @returns True if items should be removed from inventory
|
||||
*/
|
||||
public shouldQuestItemsBeRemovedOnDeath(): boolean
|
||||
{
|
||||
return this.lostOnDeathConfig.questItems;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check items array and add an upd object to money with a stack count of 1
|
||||
* Single stack money items have no upd object and thus no StackObjectsCount, causing issues
|
||||
* @param items Items array to check
|
||||
*/
|
||||
public addStackCountToMoneyFromRaid(items: Item[]): void
|
||||
{
|
||||
for (const moneyItem of items.filter((item) => this.paymentHelper.isMoneyTpl(item._tpl)))
|
||||
{
|
||||
this.itemHelper.addUpdObjectToItem(moneyItem);
|
||||
|
||||
if (!moneyItem.upd.StackObjectsCount)
|
||||
{
|
||||
moneyItem.upd.StackObjectsCount = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset a profile to a baseline, used post-raid
|
||||
* Reset points earned during session property
|
||||
* Increment exp
|
||||
* @param profileData Profile to update
|
||||
* @param saveProgressRequest post raid save data request data
|
||||
* @param sessionID Session id
|
||||
* @returns Reset profile object
|
||||
*/
|
||||
public updateProfileBaseStats(
|
||||
profileData: IPmcData,
|
||||
saveProgressRequest: ISaveProgressRequestData,
|
||||
sessionID: string,
|
||||
): void
|
||||
{
|
||||
// Remove skill fatigue values
|
||||
this.resetSkillPointsEarnedDuringRaid(saveProgressRequest.profile);
|
||||
|
||||
// Set profile data
|
||||
profileData.Info.Level = saveProgressRequest.profile.Info.Level;
|
||||
profileData.Skills = saveProgressRequest.profile.Skills;
|
||||
profileData.Stats.Eft = saveProgressRequest.profile.Stats.Eft;
|
||||
|
||||
profileData.Encyclopedia = saveProgressRequest.profile.Encyclopedia;
|
||||
profileData.TaskConditionCounters = saveProgressRequest.profile.TaskConditionCounters;
|
||||
|
||||
this.validateTaskConditionCounters(saveProgressRequest, profileData);
|
||||
|
||||
profileData.SurvivorClass = saveProgressRequest.profile.SurvivorClass;
|
||||
|
||||
// Add experience points
|
||||
profileData.Info.Experience += profileData.Stats.Eft.TotalSessionExperience;
|
||||
profileData.Stats.Eft.TotalSessionExperience = 0;
|
||||
|
||||
this.setPlayerInRaidLocationStatusToNone(sessionID);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -128,362 +36,6 @@ export class InRaidHelper
|
||||
}
|
||||
}
|
||||
|
||||
/** Check counters are correct in profile */
|
||||
protected validateTaskConditionCounters(
|
||||
saveProgressRequest: ISaveProgressRequestData,
|
||||
profileData: IPmcData,
|
||||
): void
|
||||
{
|
||||
for (const backendCounterKey in saveProgressRequest.profile.TaskConditionCounters)
|
||||
{
|
||||
// Skip counters with no id
|
||||
if (!saveProgressRequest.profile.TaskConditionCounters[backendCounterKey].id)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const postRaidValue = saveProgressRequest.profile.TaskConditionCounters[backendCounterKey]?.value;
|
||||
if (typeof postRaidValue === "undefined")
|
||||
{
|
||||
// No value, skip
|
||||
continue;
|
||||
}
|
||||
|
||||
const matchingPreRaidCounter = profileData.TaskConditionCounters[backendCounterKey];
|
||||
if (!matchingPreRaidCounter)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("inraid-unable_to_find_key_in_taskconditioncounters", backendCounterKey));
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
if (matchingPreRaidCounter.value !== postRaidValue)
|
||||
{
|
||||
this.logger.error(this.localisationService.getText("inraid-taskconditioncounter_keys_differ",
|
||||
{ key: backendCounterKey, oldValue: matchingPreRaidCounter.value, newValue: postRaidValue }));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Update various serverPMC profile values; quests/limb hp/trader standing with values post-raic
|
||||
* @param pmcData Server PMC profile
|
||||
* @param saveProgressRequest Post-raid request data
|
||||
* @param sessionId Session id
|
||||
*/
|
||||
public updatePmcProfileDataPostRaid(
|
||||
pmcData: IPmcData,
|
||||
saveProgressRequest: ISaveProgressRequestData,
|
||||
sessionId: string,
|
||||
): void
|
||||
{
|
||||
// Process failed quests then copy everything
|
||||
this.processAlteredQuests(sessionId, pmcData, pmcData.Quests, saveProgressRequest.profile);
|
||||
pmcData.Quests = saveProgressRequest.profile.Quests;
|
||||
|
||||
// No need to do this for scav, old scav is deleted and new one generated
|
||||
this.transferPostRaidLimbEffectsToProfile(saveProgressRequest, pmcData);
|
||||
|
||||
// Trader standing only occur on pmc profile, scav kills are handled in handlePostRaidPlayerScavKarmaChanges()
|
||||
// Scav client data has standing values of 0 for all traders, DO NOT RUN ON SCAV RAIDS
|
||||
this.applyTraderStandingAdjustments(pmcData.TradersInfo, saveProgressRequest.profile.TradersInfo);
|
||||
|
||||
this.updateProfileAchievements(pmcData, saveProgressRequest.profile.Achievements);
|
||||
|
||||
this.profileFixerService.checkForAndFixPmcProfileIssues(pmcData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update scav quest values on server profile with updated values post-raid
|
||||
* @param scavData Server scav profile
|
||||
* @param saveProgressRequest Post-raid request data
|
||||
* @param sessionId Session id
|
||||
*/
|
||||
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
|
||||
const existingActiveQuestIds = scavData.Quests
|
||||
?.filter((quest) => quest.status !== QuestStatus.AvailableForStart)
|
||||
.map((x) => x.qid);
|
||||
if (existingActiveQuestIds)
|
||||
{
|
||||
scavData.Quests = saveProgressRequest.profile.Quests
|
||||
.filter((quest) => existingActiveQuestIds.includes(quest.qid));
|
||||
}
|
||||
|
||||
this.profileFixerService.checkForAndFixScavProfileIssues(scavData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Look for quests with a status different from what it began the raid with
|
||||
* @param sessionId Player id
|
||||
* @param pmcData Player profile
|
||||
* @param preRaidQuests Quests prior to starting raid
|
||||
* @param postRaidProfile Profile sent by client with post-raid quests
|
||||
*/
|
||||
protected processAlteredQuests(
|
||||
sessionId: string,
|
||||
pmcData: IPmcData,
|
||||
preRaidQuests: IQuestStatus[],
|
||||
postRaidProfile: IPostRaidPmcData,
|
||||
): void
|
||||
{
|
||||
// TODO: this may break when locked quests are added to profile but player has completed no quests prior to raid
|
||||
if (!preRaidQuests)
|
||||
{
|
||||
// No quests to compare against, skip
|
||||
return;
|
||||
}
|
||||
|
||||
// Loop over all quests from post-raid profile
|
||||
const newLockedQuests: IQuestStatus[] = [];
|
||||
for (const postRaidQuest of postRaidProfile.Quests)
|
||||
{
|
||||
// postRaidQuest.status has a weird value, need to do some nasty casting to compare it
|
||||
const postRaidQuestStatus = <string>(<unknown>postRaidQuest.status);
|
||||
|
||||
// Find matching pre-raid quest, skip if we can't
|
||||
const preRaidQuest = preRaidQuests?.find((preRaidQuest) => preRaidQuest.qid === postRaidQuest.qid);
|
||||
if (!preRaidQuest)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Already completed/failed before raid, skip
|
||||
if ([QuestStatus.Fail, QuestStatus.Success].includes(preRaidQuest.status))
|
||||
{
|
||||
// Daily quests get their status altered in-raid to "AvailableForStart",
|
||||
// Copy pre-raid status to post raid data
|
||||
if (preRaidQuest.status === QuestStatus.Success)
|
||||
{
|
||||
postRaidQuest.status = QuestStatus.Success;
|
||||
}
|
||||
|
||||
if (preRaidQuest.status === QuestStatus.Fail)
|
||||
{
|
||||
postRaidQuest.status = QuestStatus.Fail;
|
||||
}
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Quest with time-gate has unlocked
|
||||
if (
|
||||
postRaidQuestStatus === "AvailableAfter"
|
||||
&& postRaidQuest.availableAfter <= this.timeUtil.getTimestamp()
|
||||
)
|
||||
{
|
||||
// Flag as ready to start
|
||||
postRaidQuest.status = QuestStatus.AvailableForStart;
|
||||
postRaidQuest.statusTimers[QuestStatus.AvailableForStart] = this.timeUtil.getTimestamp();
|
||||
|
||||
this.logger.debug(`Time-locked quest ${postRaidQuest.qid} is now ready to start`);
|
||||
|
||||
continue;
|
||||
}
|
||||
|
||||
// Quest failed inside raid
|
||||
if (postRaidQuestStatus === "Fail")
|
||||
{
|
||||
// Send failed message
|
||||
const failBody: IFailQuestRequestData = {
|
||||
Action: "QuestFail",
|
||||
qid: postRaidQuest.qid,
|
||||
removeExcessItems: true,
|
||||
};
|
||||
this.questHelper.failQuest(pmcData, failBody, sessionId);
|
||||
}
|
||||
// Restartable quests need special actions
|
||||
else if (postRaidQuestStatus === "FailRestartable")
|
||||
{
|
||||
this.handleFailRestartableQuestStatus(pmcData, postRaidProfile, postRaidQuest);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected handleFailRestartableQuestStatus(
|
||||
pmcData: IPmcData,
|
||||
postRaidProfile: IPostRaidPmcData,
|
||||
postRaidQuest: IQuestStatus): void
|
||||
{
|
||||
// Does failed quest have requirement to collect items from raid
|
||||
const questDbData = this.questHelper.getQuestFromDb(postRaidQuest.qid, pmcData);
|
||||
|
||||
// AvailableForFinish
|
||||
const matchingAffFindConditions = questDbData.conditions.AvailableForFinish.filter(
|
||||
(condition) => condition.conditionType === "FindItem",
|
||||
);
|
||||
const itemsToCollect: string[] = [];
|
||||
if (matchingAffFindConditions)
|
||||
{
|
||||
// Find all items the failed quest wanted
|
||||
for (const condition of matchingAffFindConditions)
|
||||
{
|
||||
itemsToCollect.push(...condition.target);
|
||||
}
|
||||
}
|
||||
|
||||
// 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
|
||||
postRaidProfile.Stats.Eft.CarriedQuestItems = postRaidProfile.Stats.Eft.CarriedQuestItems.filter(
|
||||
(carriedQuestItem) => !itemsToCollect.includes(carriedQuestItem),
|
||||
);
|
||||
|
||||
// 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
|
||||
for (const itemTpl of itemsToCollect)
|
||||
{
|
||||
// Look for sessioncounter and remove it
|
||||
const counterIndex = postRaidProfile.Stats.Eft.SessionCounters.Items.findIndex(
|
||||
(counter) => counter.Key.includes(itemTpl) && counter.Key.includes("LootItem"),
|
||||
);
|
||||
if (counterIndex > -1)
|
||||
{
|
||||
postRaidProfile.Stats.Eft.SessionCounters.Items.splice(counterIndex, 1);
|
||||
}
|
||||
|
||||
// Look for quest item and remove it
|
||||
const inventoryItemIndex = postRaidProfile.Inventory.items.findIndex((x) => x._tpl === itemTpl);
|
||||
if (inventoryItemIndex > -1)
|
||||
{
|
||||
postRaidProfile.Inventory.items.splice(inventoryItemIndex, 1);
|
||||
}
|
||||
}
|
||||
|
||||
// Clear out any completed conditions
|
||||
postRaidQuest.completedConditions = [];
|
||||
}
|
||||
|
||||
/**
|
||||
* Take body part effects from client profile and apply to server profile
|
||||
* @param saveProgressRequest post-raid request
|
||||
* @param profileData player profile on server
|
||||
*/
|
||||
protected transferPostRaidLimbEffectsToProfile(
|
||||
saveProgressRequest: ISaveProgressRequestData,
|
||||
profileData: IPmcData,
|
||||
): void
|
||||
{
|
||||
// Iterate over each body part
|
||||
for (const bodyPartId in saveProgressRequest.profile.Health.BodyParts)
|
||||
{
|
||||
// Get effects on body part from profile
|
||||
const bodyPartEffects = saveProgressRequest.profile.Health.BodyParts[bodyPartId].Effects;
|
||||
for (const effect in bodyPartEffects)
|
||||
{
|
||||
const effectDetails = bodyPartEffects[effect];
|
||||
|
||||
// Null guard
|
||||
if (!profileData.Health.BodyParts[bodyPartId].Effects)
|
||||
{
|
||||
profileData.Health.BodyParts[bodyPartId].Effects = {};
|
||||
}
|
||||
|
||||
// Already exists on server profile, skip
|
||||
const profileBodyPartEffects = profileData.Health.BodyParts[bodyPartId].Effects;
|
||||
if (profileBodyPartEffects[effect])
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Add effect to server profile
|
||||
profileBodyPartEffects[effect] = { Time: effectDetails.Time ?? -1 };
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Adjust server trader settings if they differ from data sent by client
|
||||
* @param tradersServerProfile Server
|
||||
* @param tradersClientProfile Client
|
||||
*/
|
||||
protected applyTraderStandingAdjustments(
|
||||
tradersServerProfile: Record<string, TraderInfo>,
|
||||
tradersClientProfile: Record<string, TraderInfo>,
|
||||
): void
|
||||
{
|
||||
for (const traderId in tradersClientProfile)
|
||||
{
|
||||
if (traderId === Traders.FENCE)
|
||||
{
|
||||
// Taking a car extract adjusts fence rep values via client/match/offline/end, skip fence for this check
|
||||
continue;
|
||||
}
|
||||
|
||||
const serverProfileTrader = tradersServerProfile[traderId];
|
||||
const clientProfileTrader = tradersClientProfile[traderId];
|
||||
if (!(serverProfileTrader && clientProfileTrader))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
if (clientProfileTrader.standing !== serverProfileTrader.standing)
|
||||
{
|
||||
// Difference found, update server profile with values from client profile
|
||||
tradersServerProfile[traderId].standing = clientProfileTrader.standing;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Transfer client achievements into profile
|
||||
* @param profile Player pmc profile
|
||||
* @param clientAchievements Achievements from client
|
||||
*/
|
||||
protected updateProfileAchievements(profile: IPmcData, clientAchievements: Record<string, number>): void
|
||||
{
|
||||
profile.Achievements ||= {};
|
||||
|
||||
for (const achievementId in clientAchievements)
|
||||
{
|
||||
profile.Achievements[achievementId] = clientAchievements[achievementId];
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the SPT inraid location Profile property to 'none'
|
||||
* @param sessionID Session id
|
||||
*/
|
||||
protected setPlayerInRaidLocationStatusToNone(sessionID: string): void
|
||||
{
|
||||
this.saveServer.getProfile(sessionID).inraid.location = "none";
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate over inventory items and remove the property that defines an item as Found in Raid
|
||||
* Only removes property if item had FiR when entering raid
|
||||
* @param postRaidProfile profile to update items for
|
||||
* @returns Updated profile with SpawnedInSession removed
|
||||
*/
|
||||
public removeSpawnedInSessionPropertyFromItems(postRaidProfile: IPostRaidPmcData): IPostRaidPmcData
|
||||
{
|
||||
const dbItems = this.databaseService.getItems();
|
||||
const itemsToRemovePropertyFrom = postRaidProfile.Inventory.items.filter((item) =>
|
||||
{
|
||||
// Has upd object + upd.SpawnedInSession property + not a quest item
|
||||
return (
|
||||
"upd" in item
|
||||
&& "SpawnedInSession" in item.upd
|
||||
&& !dbItems[item._tpl]._props.QuestItem
|
||||
&& !(
|
||||
this.inRaidConfig.keepFiRSecureContainerOnDeath
|
||||
&& this.itemHelper.itemIsInsideContainer(item, "SecuredContainer", postRaidProfile.Inventory.items)
|
||||
)
|
||||
);
|
||||
});
|
||||
|
||||
for (const item of itemsToRemovePropertyFrom)
|
||||
{
|
||||
delete item.upd.SpawnedInSession;
|
||||
}
|
||||
|
||||
return postRaidProfile;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a players inventory post-raid
|
||||
* Remove equipped items from pre-raid
|
||||
@ -564,25 +116,6 @@ export class InRaidHelper
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get items in vest/pocket/backpack inventory containers (excluding children)
|
||||
* @param pmcData Player profile
|
||||
* @returns Item array
|
||||
*/
|
||||
protected getBaseItemsInRigPocketAndBackpack(pmcData: IPmcData): Item[]
|
||||
{
|
||||
const items = pmcData.Inventory.items;
|
||||
const rig = items.find((x) => x.slotId === "TacticalVest");
|
||||
const pockets = items.find((x) => x.slotId === "Pockets");
|
||||
const backpack = items.find((x) => x.slotId === "Backpack");
|
||||
|
||||
const baseItemsInRig = items.filter((x) => x.parentId === rig?._id);
|
||||
const baseItemsInPockets = items.filter((x) => x.parentId === pockets?._id);
|
||||
const baseItemsInBackpack = items.filter((x) => x.parentId === backpack?._id);
|
||||
|
||||
return [...baseItemsInRig, ...baseItemsInPockets, ...baseItemsInBackpack];
|
||||
}
|
||||
|
||||
/**
|
||||
* Does the provided items slotId mean its kept on the player after death
|
||||
* @pmcData Player profile
|
||||
@ -635,75 +168,4 @@ export class InRaidHelper
|
||||
// All other cases item is lost
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated
|
||||
* Return the equipped items from a players inventory
|
||||
* @param items Players inventory to search through
|
||||
* @returns an array of equipped items
|
||||
*/
|
||||
public getPlayerGear(items: Item[]): Item[]
|
||||
{
|
||||
// Player Slots we care about
|
||||
const inventorySlots = [
|
||||
"FirstPrimaryWeapon",
|
||||
"SecondPrimaryWeapon",
|
||||
"Holster",
|
||||
"Scabbard",
|
||||
"Compass",
|
||||
"Headwear",
|
||||
"Earpiece",
|
||||
"Eyewear",
|
||||
"FaceCover",
|
||||
"ArmBand",
|
||||
"ArmorVest",
|
||||
"TacticalVest",
|
||||
"Backpack",
|
||||
"pocket1",
|
||||
"pocket2",
|
||||
"pocket3",
|
||||
"pocket4",
|
||||
"SpecialSlot1",
|
||||
"SpecialSlot2",
|
||||
"SpecialSlot3",
|
||||
];
|
||||
|
||||
let inventoryItems: Item[] = [];
|
||||
|
||||
// Get an array of root player items
|
||||
for (const item of items)
|
||||
{
|
||||
if (inventorySlots.includes(item.slotId))
|
||||
{
|
||||
inventoryItems.push(item);
|
||||
}
|
||||
}
|
||||
|
||||
// Loop through these items and get all of their children
|
||||
let newItems = inventoryItems;
|
||||
while (newItems.length > 0)
|
||||
{
|
||||
const foundItems = [];
|
||||
|
||||
for (const item of newItems)
|
||||
{
|
||||
// Find children of this item
|
||||
for (const newItem of items)
|
||||
{
|
||||
if (newItem.parentId === item._id)
|
||||
{
|
||||
foundItems.push(newItem);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Add these new found items to our list of inventory items
|
||||
inventoryItems = [...inventoryItems, ...foundItems];
|
||||
|
||||
// Now find the children of these items
|
||||
newItems = foundItems;
|
||||
}
|
||||
|
||||
return inventoryItems;
|
||||
}
|
||||
}
|
||||
|
@ -3,11 +3,7 @@ import { ISyncHealthRequestData } from "@spt/models/eft/health/ISyncHealthReques
|
||||
import { IInsuredItemsData } from "@spt/models/eft/inRaid/IInsuredItemsData";
|
||||
import { PlayerRaidEndState } from "@spt/models/enums/PlayerRaidEndState";
|
||||
|
||||
export interface ISaveProgressRequestData
|
||||
export interface IScavSaveRequestData
|
||||
{
|
||||
exit: PlayerRaidEndState // survived" | "killed" | "left" | "runner" | "missinginaction
|
||||
profile: IPostRaidPmcData
|
||||
isPlayerScav: boolean
|
||||
health: ISyncHealthRequestData
|
||||
insurance: IInsuredItemsData[]
|
||||
}
|
@ -1,16 +0,0 @@
|
||||
import { IEmptyRequestData } from "@spt/models/eft/common/IEmptyRequestData";
|
||||
import { INullResponseData } from "@spt/models/eft/httpResponse/INullResponseData";
|
||||
import { IRegisterPlayerRequestData } from "@spt/models/eft/inRaid/IRegisterPlayerRequestData";
|
||||
import { ISaveProgressRequestData } from "@spt/models/eft/inRaid/ISaveProgressRequestData";
|
||||
import { ISptProfile } from "@spt/models/eft/profile/ISptProfile";
|
||||
|
||||
export interface IInraidCallbacks
|
||||
{
|
||||
onLoad(sessionID: string): ISptProfile
|
||||
registerPlayer(url: string, info: IRegisterPlayerRequestData, sessionID: string): INullResponseData
|
||||
saveProgress(url: string, info: ISaveProgressRequestData, sessionID: string): INullResponseData
|
||||
getRaidEndState(): string
|
||||
getRaidMenuSettings(url: string, info: IEmptyRequestData, sessionID: string): string
|
||||
getWeaponDurability(url: string, info: any, sessionID: string): string
|
||||
getAirdropConfig(url: string, info: any, sessionID: string): string
|
||||
}
|
@ -10,7 +10,7 @@ export class InraidStaticRouter extends StaticRouter
|
||||
{
|
||||
super([
|
||||
new RouteAction(
|
||||
"/raid/profile/save",
|
||||
"/raid/profile/scavsave",
|
||||
async (url: string, info: any, sessionID: string, output: string): Promise<INullResponseData> =>
|
||||
{
|
||||
return this.inraidCallbacks.saveProgress(url, info, sessionID);
|
||||
|
@ -1,26 +1,19 @@
|
||||
import { inject, injectable } from "tsyringe";
|
||||
import { DialogueHelper } from "@spt/helpers/DialogueHelper";
|
||||
import { HandbookHelper } from "@spt/helpers/HandbookHelper";
|
||||
import { ItemHelper } from "@spt/helpers/ItemHelper";
|
||||
import { SecureContainerHelper } from "@spt/helpers/SecureContainerHelper";
|
||||
import { TraderHelper } from "@spt/helpers/TraderHelper";
|
||||
import { IPmcData } from "@spt/models/eft/common/IPmcData";
|
||||
import { Item } from "@spt/models/eft/common/tables/IItem";
|
||||
import { ITraderBase } from "@spt/models/eft/common/tables/ITrader";
|
||||
import { IInsuredItemsData } from "@spt/models/eft/inRaid/IInsuredItemsData";
|
||||
import { ISaveProgressRequestData } from "@spt/models/eft/inRaid/ISaveProgressRequestData";
|
||||
import { BonusType } from "@spt/models/enums/BonusType";
|
||||
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
|
||||
import { ItemTpl } from "@spt/models/enums/ItemTpl";
|
||||
import { MessageType } from "@spt/models/enums/MessageType";
|
||||
import { IInsuranceConfig } from "@spt/models/spt/config/IInsuranceConfig";
|
||||
import { ILostOnDeathConfig } from "@spt/models/spt/config/ILostOnDeathConfig";
|
||||
import { IInsuranceEquipmentPkg } from "@spt/models/spt/services/IInsuranceEquipmentPkg";
|
||||
import { ILogger } from "@spt/models/spt/utils/ILogger";
|
||||
import { ConfigServer } from "@spt/servers/ConfigServer";
|
||||
import { SaveServer } from "@spt/servers/SaveServer";
|
||||
import { DatabaseService } from "@spt/services/DatabaseService";
|
||||
import { LocaleService } from "@spt/services/LocaleService";
|
||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
||||
import { MailSendService } from "@spt/services/MailSendService";
|
||||
import { ICloner } from "@spt/utils/cloners/ICloner";
|
||||
@ -33,29 +26,23 @@ export class InsuranceService
|
||||
{
|
||||
protected insured: Record<string, Record<string, Item[]>> = {};
|
||||
protected insuranceConfig: IInsuranceConfig;
|
||||
protected lostOnDeathConfig: ILostOnDeathConfig;
|
||||
|
||||
constructor(
|
||||
@inject("PrimaryLogger") protected logger: ILogger,
|
||||
@inject("DatabaseService") protected databaseService: DatabaseService,
|
||||
@inject("SecureContainerHelper") protected secureContainerHelper: SecureContainerHelper,
|
||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||
@inject("TimeUtil") protected timeUtil: TimeUtil,
|
||||
@inject("SaveServer") protected saveServer: SaveServer,
|
||||
@inject("TraderHelper") protected traderHelper: TraderHelper,
|
||||
@inject("DialogueHelper") protected dialogueHelper: DialogueHelper,
|
||||
@inject("HandbookHelper") protected handbookHelper: HandbookHelper,
|
||||
@inject("LocalisationService") protected localisationService: LocalisationService,
|
||||
@inject("LocaleService") protected localeService: LocaleService,
|
||||
@inject("MailSendService") protected mailSendService: MailSendService,
|
||||
@inject("ConfigServer") protected configServer: ConfigServer,
|
||||
@inject("PrimaryCloner") protected cloner: ICloner,
|
||||
)
|
||||
{
|
||||
this.insuranceConfig = this.configServer.getConfig(ConfigTypes.INSURANCE);
|
||||
this.lostOnDeathConfig = this.configServer.getConfig(ConfigTypes.LOST_ON_DEATH);
|
||||
}
|
||||
|
||||
/**
|
||||
@ -78,17 +65,6 @@ export class InsuranceService
|
||||
return this.insured[sessionId];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get insured items by profile id + trader id
|
||||
* @param sessionId Profile id (session id)
|
||||
* @param traderId Trader items were insured with
|
||||
* @returns Item array
|
||||
*/
|
||||
public getInsuranceItems(sessionId: string, traderId: string): Item[]
|
||||
{
|
||||
return this.insured[sessionId][traderId];
|
||||
}
|
||||
|
||||
public resetInsurance(sessionId: string): void
|
||||
{
|
||||
this.insured[sessionId] = {};
|
||||
@ -158,27 +134,6 @@ export class InsuranceService
|
||||
this.resetInsurance(sessionID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check all root insured items and remove location property + set slotId to 'hideout'
|
||||
* @param sessionId Session id
|
||||
* @param traderId Trader id
|
||||
*/
|
||||
protected removeLocationProperty(sessionId: string, traderId: string): void
|
||||
{
|
||||
const insuredItems = this.getInsurance(sessionId)[traderId];
|
||||
for (const insuredItem of this.getInsurance(sessionId)[traderId])
|
||||
{
|
||||
// Find insured items parent
|
||||
const insuredItemsParent = insuredItems.some((x) => x._id === insuredItem.parentId);
|
||||
if (!insuredItemsParent)
|
||||
{
|
||||
// Remove location + set slotId of insured items parent
|
||||
insuredItem.slotId = "hideout";
|
||||
delete insuredItem.location;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a timestamp of when insurance items should be sent to player based on trader used to insure
|
||||
* Apply insurance return bonus if found in profile
|
||||
@ -228,143 +183,6 @@ export class InsuranceService
|
||||
return this.timeUtil.getTimestamp() + randomisedReturnTimeSeconds * insuranceReturnTimeBonusPercent;
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated - Client now handles this
|
||||
* Create insurance equipment packages that should be sent to the user. The packages should contain items that have
|
||||
* been lost in a raid and should be returned to the player through the insurance system.
|
||||
*
|
||||
* NOTE: We do not have data on items that were dropped in a raid. This means we have to pull item data from the
|
||||
* profile at the start of the raid to return to the player in insurance. Because of this, the item
|
||||
* positioning may differ from the position the item was in when the player died. Apart from removing all
|
||||
* positioning, this is the best we can do. >:{}
|
||||
*
|
||||
* @param pmcData Player profile
|
||||
* @param offraidData Post-raid data
|
||||
* @param preRaidGear Pre-raid data
|
||||
* @param sessionID Session id
|
||||
* @param playerDied Did player die in raid
|
||||
* @returns Array of insured items lost in raid
|
||||
*/
|
||||
public getGearLostInRaid(
|
||||
pmcData: IPmcData,
|
||||
offraidData: ISaveProgressRequestData,
|
||||
preRaidGear: Item[],
|
||||
sessionID: string,
|
||||
playerDied: boolean,
|
||||
): IInsuranceEquipmentPkg[]
|
||||
{
|
||||
const equipmentPkg: IInsuranceEquipmentPkg[] = [];
|
||||
const preRaidGearMap = this.itemHelper.generateItemsMap(preRaidGear);
|
||||
const offRaidGearMap = this.itemHelper.generateItemsMap(offraidData.profile.Inventory.items);
|
||||
|
||||
for (const insuredItem of pmcData.InsuredItems)
|
||||
{
|
||||
// Skip insured items not on player when they started the raid.
|
||||
if (!preRaidGearMap.has(insuredItem.itemId))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
const preRaidItem = preRaidGearMap.get(insuredItem.itemId)!;
|
||||
|
||||
// Skip slots we should never return as they're never lost on death
|
||||
if (this.insuranceConfig.blacklistedEquipment.includes(preRaidItem.slotId!))
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Equipment slots can be flagged as never lost on death and shouldn't be saved in an insurance package.
|
||||
// We need to check if the item is directly equipped to an equipment slot, or if it is a child Item of an
|
||||
// equipment slot.
|
||||
const equipmentParentItem = this.itemHelper.getEquipmentParent(preRaidItem._id, preRaidGearMap);
|
||||
|
||||
const offraidDataitem = offraidData.insurance?.find(
|
||||
(insuranceItem) => insuranceItem.id === insuredItem.itemId);
|
||||
|
||||
if (offraidDataitem?.usedInQuest)
|
||||
{
|
||||
continue;
|
||||
}
|
||||
|
||||
// Now that we have the equipment parent item, we can check to see if that item is located in an equipment
|
||||
// slot that is flagged as lost on death. If it is, then the itemShouldBeLostOnDeath.
|
||||
const itemShouldBeLostOnDeath = equipmentParentItem?.slotId
|
||||
? this.lostOnDeathConfig.equipment[equipmentParentItem?.slotId] ?? true
|
||||
: true;
|
||||
|
||||
// Was the item found in the player inventory post-raid?
|
||||
const itemOnPlayerPostRaid = offRaidGearMap.has(insuredItem.itemId);
|
||||
|
||||
// Check if item missing in post-raid gear OR player died + item slot flagged as lost on death
|
||||
// Catches both events: player died with item on + player survived but dropped item in raid
|
||||
if (!itemOnPlayerPostRaid || (playerDied && itemShouldBeLostOnDeath))
|
||||
{
|
||||
const inventoryInsuredItem = offraidData.insurance
|
||||
?.find((insuranceItem) => insuranceItem.id === insuredItem.itemId);
|
||||
if (!inventoryInsuredItem)
|
||||
{
|
||||
throw new Error(this.localisationService.getText("insurance-item_not_found_in_post_raid_data", insuredItem.itemId));
|
||||
}
|
||||
|
||||
equipmentPkg.push({
|
||||
pmcData: pmcData,
|
||||
itemToReturnToPlayer: this.getInsuredItemDetails(
|
||||
pmcData,
|
||||
preRaidItem,
|
||||
inventoryInsuredItem,
|
||||
),
|
||||
traderId: insuredItem.tid,
|
||||
sessionID: sessionID,
|
||||
});
|
||||
|
||||
// Armor item with slots, we need to include soft_inserts as they can never be removed from armor items
|
||||
if (this.itemHelper.armorItemCanHoldMods(preRaidItem._tpl))
|
||||
{
|
||||
if (this.itemHelper.itemHasSlots(preRaidItem._tpl))
|
||||
{
|
||||
// Get IDs of all soft insert child items on armor from pre raid gear data
|
||||
const softInsertChildIds = preRaidGear
|
||||
.filter(
|
||||
(item) =>
|
||||
item.parentId === preRaidItem._id
|
||||
&& this.itemHelper.getSoftInsertSlotIds().includes(item.slotId!.toLowerCase()),
|
||||
)
|
||||
.map((x) => x._id);
|
||||
|
||||
// Add all items found above to return data
|
||||
for (const softInsertChildModId of softInsertChildIds)
|
||||
{
|
||||
const preRaidInventoryItem = preRaidGear.find((item) => item._id === softInsertChildModId);
|
||||
if (!preRaidInventoryItem)
|
||||
{
|
||||
throw new Error(this.localisationService.getText("insurance-pre_raid_item_not_found", softInsertChildModId));
|
||||
}
|
||||
const inventoryInsuredItem = offraidData.insurance?.find(
|
||||
(insuranceItem) => insuranceItem.id === softInsertChildModId,
|
||||
);
|
||||
if (!inventoryInsuredItem)
|
||||
{
|
||||
throw new Error(this.localisationService.getText("insurance-post_raid_item_not_found", softInsertChildModId));
|
||||
}
|
||||
equipmentPkg.push({
|
||||
pmcData: pmcData,
|
||||
itemToReturnToPlayer: this.getInsuredItemDetails(
|
||||
pmcData,
|
||||
preRaidInventoryItem,
|
||||
inventoryInsuredItem,
|
||||
),
|
||||
traderId: insuredItem.tid,
|
||||
sessionID: sessionID,
|
||||
});
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return equipmentPkg;
|
||||
}
|
||||
|
||||
/**
|
||||
* Take the insurance item packages within a profile session and ensure that each of the items in that package are
|
||||
* not orphaned from their parent ID.
|
||||
@ -398,75 +216,6 @@ export class InsuranceService
|
||||
this.adoptOrphanedInsEquipment(sessionID);
|
||||
}
|
||||
|
||||
/**
|
||||
* Take preraid item and update properties to ensure its ready to be given to player in insurance return mail
|
||||
* @param pmcData Player profile
|
||||
* @param preRaidItemWithChildren Insured item (with children) as it was pre-raid
|
||||
* @param allItemsFromClient Item data when player left raid (durability values)
|
||||
* @returns Item (with children) to send to player
|
||||
*/
|
||||
protected getInsuredItemDetails(
|
||||
pmcData: IPmcData,
|
||||
preRaidItem: Item,
|
||||
insuredItemFromClient: IInsuredItemsData,
|
||||
): Item
|
||||
{
|
||||
// Get baseline item to return, clone pre raid item
|
||||
const itemToReturnClone: Item = this.cloner.clone(preRaidItem);
|
||||
|
||||
// Add upd if it doesnt exist
|
||||
this.itemHelper.addUpdObjectToItem(itemToReturnClone);
|
||||
|
||||
// Check for slotid values that need to be updated and adjust
|
||||
this.updateSlotIdValue(pmcData.Inventory.equipment, itemToReturnClone);
|
||||
|
||||
// Remove location property
|
||||
if (itemToReturnClone.slotId === "hideout" && "location" in itemToReturnClone)
|
||||
{
|
||||
delete itemToReturnClone.location;
|
||||
}
|
||||
|
||||
// Remove found in raid status when upd exists + SpawnedInSession value exists
|
||||
if ("SpawnedInSession" in itemToReturnClone.upd!)
|
||||
{
|
||||
itemToReturnClone.upd.SpawnedInSession = false;
|
||||
}
|
||||
|
||||
// Client item has durability values, Ensure values persist into server data
|
||||
if (insuredItemFromClient?.durability)
|
||||
{
|
||||
// Item didnt have Repairable object pre-raid, add it
|
||||
if (!itemToReturnClone.upd?.Repairable)
|
||||
{
|
||||
itemToReturnClone.upd!.Repairable = {
|
||||
Durability: insuredItemFromClient.durability,
|
||||
MaxDurability: insuredItemFromClient.maxDurability!,
|
||||
};
|
||||
}
|
||||
else
|
||||
{
|
||||
itemToReturnClone.upd.Repairable.Durability = insuredItemFromClient.durability;
|
||||
itemToReturnClone.upd.Repairable.MaxDurability = insuredItemFromClient.maxDurability!;
|
||||
}
|
||||
}
|
||||
|
||||
// Client item has FaceShield values, Ensure values persist into server data
|
||||
if (insuredItemFromClient?.hits)
|
||||
{
|
||||
// Item didnt have faceshield object pre-raid, add it
|
||||
if (!itemToReturnClone.upd?.FaceShield)
|
||||
{
|
||||
itemToReturnClone.upd!.FaceShield = { Hits: insuredItemFromClient.hits };
|
||||
}
|
||||
else
|
||||
{
|
||||
itemToReturnClone.upd.FaceShield.Hits = insuredItemFromClient.hits;
|
||||
}
|
||||
}
|
||||
|
||||
return itemToReturnClone;
|
||||
}
|
||||
|
||||
/**
|
||||
* For the passed in items, find the trader it was insured against
|
||||
* @param sessionId Session id
|
||||
@ -503,28 +252,6 @@ export class InsuranceService
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Reset slotId property to "hideout" when necessary (used to be in )
|
||||
* @param pmcData Players pmcData.Inventory.equipment value
|
||||
* @param itemToReturn item we will send to player as insurance return
|
||||
*/
|
||||
protected updateSlotIdValue(playerBaseInventoryEquipmentId: string, itemToReturn: Item): void
|
||||
{
|
||||
const pocketSlots = ["pocket1", "pocket2", "pocket3", "pocket4"];
|
||||
|
||||
// Some pockets can lose items with player death, some don't
|
||||
if (!("slotId" in itemToReturn) || pocketSlots.includes(itemToReturn.slotId!))
|
||||
{
|
||||
itemToReturn.slotId = "hideout";
|
||||
}
|
||||
|
||||
// Mark root-level items for later processing
|
||||
if (itemToReturn.parentId === playerBaseInventoryEquipmentId)
|
||||
{
|
||||
itemToReturn.slotId = "hideout";
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add gear item to InsuredItems array in player profile
|
||||
* @param sessionID Session id
|
||||
|
Loading…
Reference in New Issue
Block a user