0
0
mirror of https://github.com/sp-tarkov/server.git synced 2025-02-13 09:50:43 -05:00

Rename IQuestReward and QuestRewardType to be generic

This commit is contained in:
DrakiaXYZ 2025-01-11 22:21:08 -08:00
parent accedf24c9
commit bc7935e943
12 changed files with 94 additions and 91 deletions

View File

@ -7,7 +7,7 @@ import { QuestHelper } from "@spt/helpers/QuestHelper";
import { TraderHelper } from "@spt/helpers/TraderHelper";
import { CustomisationSource } from "@spt/models/eft/common/tables/ICustomisationStorage";
import { IPrestige } from "@spt/models/eft/common/tables/IPrestige";
import { IQuestReward } from "@spt/models/eft/common/tables/IQuest";
import { IReward } from "@spt/models/eft/common/tables/IReward";
import { IAddItemDirectRequest } from "@spt/models/eft/inventory/IAddItemDirectRequest";
import { IAddItemsDirectRequest } from "@spt/models/eft/inventory/IAddItemsDirectRequest";
import { IObtainPrestigeRequest } from "@spt/models/eft/prestige/IObtainPrestigeRequest";
@ -145,7 +145,7 @@ export class PrestigeController {
}
}
protected addPrestigeRewardsToProfile(sessionId: string, newProfile: ISptProfile, rewards: IQuestReward[]) {
protected addPrestigeRewardsToProfile(sessionId: string, newProfile: ISptProfile, rewards: IReward[]) {
for (const reward of rewards) {
switch (reward.type) {
case "CustomizationDirect": {

View File

@ -2,12 +2,13 @@ import { HandbookHelper } from "@spt/helpers/HandbookHelper";
import { ItemHelper } from "@spt/helpers/ItemHelper";
import { PresetHelper } from "@spt/helpers/PresetHelper";
import { IItem } from "@spt/models/eft/common/tables/IItem";
import { IQuestReward, IQuestRewards } from "@spt/models/eft/common/tables/IQuest";
import { IQuestRewards } from "@spt/models/eft/common/tables/IQuest";
import { IReward } from "@spt/models/eft/common/tables/IReward";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { BaseClasses } from "@spt/models/enums/BaseClasses";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { Money } from "@spt/models/enums/Money";
import { QuestRewardType } from "@spt/models/enums/QuestRewardType";
import { RewardType } from "@spt/models/enums/RewardType";
import { Traders } from "@spt/models/enums/Traders";
import {
IBaseQuestConfig,
@ -104,7 +105,7 @@ export class RepeatableQuestRewardGenerator {
availableInGameEditions: [],
index: rewardIndex,
value: rewardParams.rewardXP,
type: QuestRewardType.EXPERIENCE,
type: RewardType.EXPERIENCE,
});
rewardIndex++;
}
@ -166,14 +167,14 @@ export class RepeatableQuestRewardGenerator {
// Add rep reward to rewards array
if (rewardParams.rewardReputation > 0) {
const reward: IQuestReward = {
const reward: IReward = {
id: this.hashUtil.generate(),
unknown: false,
gameMode: [],
availableInGameEditions: [],
target: traderId,
value: rewardParams.rewardReputation,
type: QuestRewardType.TRADER_STANDING,
type: RewardType.TRADER_STANDING,
index: rewardIndex,
};
rewards.Success.push(reward);
@ -185,14 +186,14 @@ export class RepeatableQuestRewardGenerator {
// Chance of adding skill reward
if (this.randomUtil.getChance100(rewardParams.skillRewardChance * 100)) {
const targetSkill = this.randomUtil.getArrayValue(questConfig.possibleSkillRewards);
const reward: IQuestReward = {
const reward: IReward = {
id: this.hashUtil.generate(),
unknown: false,
gameMode: [],
availableInGameEditions: [],
target: targetSkill,
value: rewardParams.skillPointReward,
type: QuestRewardType.SKILL,
type: RewardType.SKILL,
index: rewardIndex,
};
rewards.Success.push(reward);
@ -340,12 +341,12 @@ export class RepeatableQuestRewardGenerator {
* Choose a random Weapon preset that fits inside of a rouble amount limit
* @param roublesBudget
* @param rewardIndex
* @returns IQuestReward
* @returns IReward
*/
protected getRandomWeaponPresetWithinBudget(
roublesBudget: number,
rewardIndex: number,
): { weapon: IQuestReward; price: number } | undefined {
): { weapon: IReward; price: number } | undefined {
// Add a random default preset weapon as reward
const defaultPresetPool = new ExhaustableArray(
Object.values(this.presetHelper.getDefaultWeaponPresets()),
@ -517,9 +518,9 @@ export class RepeatableQuestRewardGenerator {
* @param preset Optional array of preset items
* @returns {object} Object of "Reward"-item-type
*/
protected generateItemReward(tpl: string, count: number, index: number, foundInRaid = true): IQuestReward {
protected generateItemReward(tpl: string, count: number, index: number, foundInRaid = true): IReward {
const id = this.hashUtil.generate();
const questRewardItem: IQuestReward = {
const questRewardItem: IReward = {
id: this.hashUtil.generate(),
unknown: false,
gameMode: [],
@ -529,7 +530,7 @@ export class RepeatableQuestRewardGenerator {
value: count,
isEncoded: false,
findInRaid: foundInRaid,
type: QuestRewardType.ITEM,
type: RewardType.ITEM,
items: [],
};
@ -554,9 +555,9 @@ export class RepeatableQuestRewardGenerator {
index: number,
preset?: IItem[],
foundInRaid = true,
): IQuestReward {
): IReward {
const id = this.hashUtil.generate();
const questRewardItem: IQuestReward = {
const questRewardItem: IReward = {
id: this.hashUtil.generate(),
unknown: false,
gameMode: [],
@ -566,7 +567,7 @@ export class RepeatableQuestRewardGenerator {
value: count,
isEncoded: false,
findInRaid: foundInRaid,
type: QuestRewardType.ITEM,
type: RewardType.ITEM,
items: [],
};
@ -667,7 +668,7 @@ export class RepeatableQuestRewardGenerator {
return true;
}
protected getMoneyReward(traderId: string, rewardRoubles: number, rewardIndex: number): IQuestReward {
protected getMoneyReward(traderId: string, rewardRoubles: number, rewardIndex: number): IReward {
// Determine currency based on trader
// PK and Fence use Euros, everyone else is Roubles
const currency = traderId === Traders.PEACEKEEPER || traderId === Traders.FENCE ? Money.EUROS : Money.ROUBLES;

View File

@ -7,7 +7,7 @@ import {
ICustomisationStorage,
} from "@spt/models/eft/common/tables/ICustomisationStorage";
import { IItem } from "@spt/models/eft/common/tables/IItem";
import { IQuestReward } from "@spt/models/eft/common/tables/IQuest";
import { IReward } from "@spt/models/eft/common/tables/IReward";
import { ISearchFriendResponse } from "@spt/models/eft/profile/ISearchFriendResponse";
import { ISpt, ISptProfile } from "@spt/models/eft/profile/ISptProfile";
import { IValidateNicknameRequestData } from "@spt/models/eft/profile/IValidateNicknameRequestData";
@ -655,11 +655,7 @@ export class ProfileHelper {
* @param reward reward given to player with customisation data
* @param source Source of reward, e.g. "unlockedInGame" for quests and "achievement" for achievements
*/
public addHideoutCustomisationUnlock(
fullProfile: ISptProfile,
reward: IQuestReward,
source: CustomisationSource,
): void {
public addHideoutCustomisationUnlock(fullProfile: ISptProfile, reward: IReward, source: CustomisationSource): void {
fullProfile.customisationUnlocks ||= [];
if (fullProfile.customisationUnlocks?.some((unlock) => unlock.id === reward.target)) {
this.logger.warning(

View File

@ -6,7 +6,8 @@ import { TraderHelper } from "@spt/helpers/TraderHelper";
import { IPmcData } from "@spt/models/eft/common/IPmcData";
import { Common, IQuestStatus } from "@spt/models/eft/common/tables/IBotBase";
import { IItem } from "@spt/models/eft/common/tables/IItem";
import { IQuest, IQuestCondition, IQuestReward } from "@spt/models/eft/common/tables/IQuest";
import { IQuest, IQuestCondition } from "@spt/models/eft/common/tables/IQuest";
import { IReward } from "@spt/models/eft/common/tables/IReward";
import { IItemEventRouterResponse } from "@spt/models/eft/itemEvent/IItemEventRouterResponse";
import { IAcceptQuestRequestData } from "@spt/models/eft/quests/IAcceptQuestRequestData";
import { ICompleteQuestRequestData } from "@spt/models/eft/quests/ICompleteQuestRequestData";
@ -1058,7 +1059,7 @@ export class QuestHelper {
for (const quest of modifiedQuests) {
// Remove any reward that doesn't pass the game edition check
for (const rewardType of Object.keys(quest.rewards)) {
quest.rewards[rewardType] = quest.rewards[rewardType].filter((reward: IQuestReward) =>
quest.rewards[rewardType] = quest.rewards[rewardType].filter((reward: IReward) =>
this.questRewardHelper.questRewardIsForGameEdition(reward, gameVersion),
);
}

View File

@ -6,10 +6,11 @@ import { TraderHelper } from "@spt/helpers/TraderHelper";
import { IPmcData } from "@spt/models/eft/common/IPmcData";
import { CustomisationSource } from "@spt/models/eft/common/tables/ICustomisationStorage";
import { IItem } from "@spt/models/eft/common/tables/IItem";
import { IQuest, IQuestReward } from "@spt/models/eft/common/tables/IQuest";
import { IQuest } from "@spt/models/eft/common/tables/IQuest";
import { IReward } from "@spt/models/eft/common/tables/IReward";
import { IHideoutProduction } from "@spt/models/eft/hideout/IHideoutProduction";
import { IItemEventRouterResponse } from "@spt/models/eft/itemEvent/IItemEventRouterResponse";
import { QuestRewardType } from "@spt/models/enums/QuestRewardType";
import { RewardType } from "@spt/models/enums/RewardType";
import { QuestStatus } from "@spt/models/enums/QuestStatus";
import { SkillTypes } from "@spt/models/enums/SkillTypes";
import type { ILogger } from "@spt/models/spt/utils/ILogger";
@ -80,46 +81,46 @@ export class QuestRewardHelper {
// e.g. 'Success' or 'AvailableForFinish'
const questStateAsString = QuestStatus[state];
const gameVersion = pmcProfile.Info.GameVersion;
for (const reward of <IQuestReward[]>questDetails.rewards[questStateAsString]) {
for (const reward of <IReward[]>questDetails.rewards[questStateAsString]) {
// Handle quest reward availability for different game versions, notAvailableInGameEditions currently not used
if (!this.questRewardIsForGameEdition(reward, gameVersion)) {
continue;
}
switch (reward.type) {
case QuestRewardType.SKILL:
case RewardType.SKILL:
this.profileHelper.addSkillPointsToPlayer(
profileData,
reward.target as SkillTypes,
Number(reward.value),
);
break;
case QuestRewardType.EXPERIENCE:
case RewardType.EXPERIENCE:
this.profileHelper.addExperienceToPmc(sessionId, Number.parseInt(<string>reward.value)); // this must occur first as the output object needs to take the modified profile exp value
break;
case QuestRewardType.TRADER_STANDING:
case RewardType.TRADER_STANDING:
this.traderHelper.addStandingToTrader(
sessionId,
reward.target,
Number.parseFloat(<string>reward.value),
);
break;
case QuestRewardType.TRADER_UNLOCK:
case RewardType.TRADER_UNLOCK:
this.traderHelper.setTraderUnlockedState(reward.target, true, sessionId);
break;
case QuestRewardType.ITEM:
case RewardType.ITEM:
// Handled by getQuestRewardItems() below
break;
case QuestRewardType.ASSORTMENT_UNLOCK:
case RewardType.ASSORTMENT_UNLOCK:
// Handled by getAssort(), locked assorts are stripped out by `assortHelper.stripLockedLoyaltyAssort()` before being sent to player
break;
case QuestRewardType.ACHIEVEMENT:
case RewardType.ACHIEVEMENT:
this.profileHelper.addAchievementToProfile(fullProfile, reward.target);
break;
case QuestRewardType.STASH_ROWS:
case RewardType.STASH_ROWS:
this.profileHelper.addStashRowsBonusToProfile(sessionId, Number.parseInt(<string>reward.value)); // Add specified stash rows from quest reward - requires client restart
break;
case QuestRewardType.PRODUCTIONS_SCHEME:
case RewardType.PRODUCTIONS_SCHEME:
this.findAndAddHideoutProductionIdToProfile(
pmcProfile,
reward,
@ -128,10 +129,10 @@ export class QuestRewardHelper {
questResponse,
);
break;
case QuestRewardType.POCKETS:
case RewardType.POCKETS:
this.profileHelper.replaceProfilePocketTpl(pmcProfile, reward.target);
break;
case QuestRewardType.CUSTOMIZATION_DIRECT:
case RewardType.CUSTOMIZATION_DIRECT:
this.profileHelper.addHideoutCustomisationUnlock(
fullProfile,
reward,
@ -159,7 +160,7 @@ export class QuestRewardHelper {
* @param gameVersion Version of game to check reward against
* @returns True if it has requirement, false if it doesnt pass check
*/
public questRewardIsForGameEdition(reward: IQuestReward, gameVersion: string) {
public questRewardIsForGameEdition(reward: IReward, gameVersion: string) {
if (reward.availableInGameEditions?.length > 0 && !reward.availableInGameEditions?.includes(gameVersion)) {
// Reward has edition whitelist and game version isnt in it
return false;
@ -229,7 +230,7 @@ export class QuestRewardHelper {
* @returns Updated quest
*/
public applyMoneyBoost(quest: IQuest, bonusPercent: number, questStatus: QuestStatus): IQuest {
const rewards: IQuestReward[] = quest.rewards?.[QuestStatus[questStatus]] ?? [];
const rewards: IReward[] = quest.rewards?.[QuestStatus[questStatus]] ?? [];
const currencyRewards = rewards.filter(
(reward) => reward.type === "Item" && this.paymentHelper.isMoneyTpl(reward.items[0]._tpl),
);
@ -255,7 +256,7 @@ export class QuestRewardHelper {
*/
protected findAndAddHideoutProductionIdToProfile(
pmcData: IPmcData,
craftUnlockReward: IQuestReward,
craftUnlockReward: IReward,
questDetails: IQuest,
sessionID: string,
response: IItemEventRouterResponse,
@ -284,7 +285,7 @@ export class QuestRewardHelper {
* @param questDetails Quest with craft unlock reward
* @returns Hideout craft
*/
public getRewardProductionMatch(craftUnlockReward: IQuestReward, questDetails: IQuest): IHideoutProduction[] {
public getRewardProductionMatch(craftUnlockReward: IReward, questDetails: IQuest): IHideoutProduction[] {
// Get hideout crafts and find those that match by areatype/required level/end product tpl - hope for just one match
const craftingRecipes = this.databaseService.getHideout().production.recipes;
@ -324,7 +325,7 @@ export class QuestRewardHelper {
}
// 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: IReward) =>
reward.type === "Item" && this.questRewardIsForGameEdition(reward, gameVersion)
? this.processReward(reward)
: [],
@ -338,7 +339,7 @@ export class QuestRewardHelper {
* @param questReward Reward item to fix
* @returns Fixed rewards
*/
protected processReward(questReward: IQuestReward): IItem[] {
protected processReward(questReward: IReward): IItem[] {
/** item with mods to return */
let rewardItems: IItem[] = [];
let targets: IItem[] = [];
@ -407,10 +408,10 @@ export class QuestRewardHelper {
/**
* Add missing mod items to a quest armor reward
* @param originalRewardRootItem Original armor reward item from IQuestReward.items object
* @param originalRewardRootItem Original armor reward item from IReward.items object
* @param questReward Armor reward from quest
*/
protected generateArmorRewardChildSlots(originalRewardRootItem: IItem, questReward: IQuestReward): void {
protected generateArmorRewardChildSlots(originalRewardRootItem: IItem, questReward: IReward): void {
// Look for a default preset from globals for armor
const defaultPreset = this.presetHelper.getDefaultPreset(originalRewardRootItem._tpl);
if (defaultPreset) {

View File

@ -1,10 +1,11 @@
import { IQuestConditionTypes, IQuestReward } from "@spt/models/eft/common/tables/IQuest";
import { IQuestConditionTypes } from "@spt/models/eft/common/tables/IQuest";
import { IReward } from "@spt/models/eft/common/tables/IReward";
export interface IAchievement {
id: string;
imageUrl: string;
assetPath: string;
rewards: IQuestReward[];
rewards: IReward[];
conditions: IQuestConditionTypes;
instantComplete: boolean;
showNotificationsInGame: boolean;

View File

@ -1,4 +1,5 @@
import type { IQuestCondition, IQuestReward } from "./IQuest";
import type { IQuestCondition } from "@spt/models/eft/common/tables/IQuest";
import type { IReward } from "@spt/models/eft/common/tables/IReward";
export interface IPrestige {
elements: IPretigeElement[];
@ -7,7 +8,7 @@ export interface IPrestige {
export interface IPretigeElement {
id: string;
conditions: IQuestCondition[];
rewards: IQuestReward[];
rewards: IReward[];
transferConfigs: ITransferConfigs;
image: string;
bigImage: string;

View File

@ -1,5 +1,4 @@
import { IItem } from "@spt/models/eft/common/tables/IItem";
import { QuestRewardType } from "@spt/models/enums/QuestRewardType";
import { IReward } from "@spt/models/eft/common/tables/IReward";
import { QuestStatus } from "@spt/models/enums/QuestStatus";
import { QuestTypeEnum } from "@spt/models/enums/QuestTypeEnum";
@ -146,33 +145,11 @@ export interface IVisibilityCondition {
}
export interface IQuestRewards {
AvailableForStart?: IQuestReward[];
AvailableForFinish?: IQuestReward[];
Started?: IQuestReward[];
Success?: IQuestReward[];
Fail?: IQuestReward[];
FailRestartable?: IQuestReward[];
Expired?: IQuestReward[];
}
export interface IQuestReward {
value?: string | number;
id?: string;
illustrationConfig?: any;
isHidden?: boolean;
type: QuestRewardType;
index: number;
target?: string;
items?: IItem[];
loyaltyLevel?: number;
/** Hideout area id */
traderId?: string;
isEncoded?: boolean;
unknown?: boolean;
findInRaid?: boolean;
gameMode?: string[];
/** Game editions whitelisted to get reward */
availableInGameEditions?: string[];
/** Game editions blacklisted from getting reward */
notAvailableInGameEditions?: string[];
AvailableForStart?: IReward[];
AvailableForFinish?: IReward[];
Started?: IReward[];
Success?: IReward[];
Fail?: IReward[];
FailRestartable?: IReward[];
Expired?: IReward[];
}

View File

@ -0,0 +1,24 @@
import { RewardType } from "@spt/models/enums/RewardType";
import { IItem } from "./IItem";
export interface IReward {
value?: string | number;
id?: string;
illustrationConfig?: any;
isHidden?: boolean;
type: RewardType;
index: number;
target?: string;
items?: IItem[];
loyaltyLevel?: number;
/** Hideout area id */
traderId?: string;
isEncoded?: boolean;
unknown?: boolean;
findInRaid?: boolean;
gameMode?: string[];
/** Game editions whitelisted to get reward */
availableInGameEditions?: string[];
/** Game editions blacklisted from getting reward */
notAvailableInGameEditions?: string[];
}

View File

@ -1,4 +1,4 @@
export enum QuestRewardType {
export enum RewardType {
SKILL = "Skill",
EXPERIENCE = "Experience",
TRADER_STANDING = "TraderStanding",

View File

@ -6,7 +6,8 @@ import { QuestRewardHelper } from "@spt/helpers/QuestRewardHelper";
import { TraderHelper } from "@spt/helpers/TraderHelper";
import { IPmcData } from "@spt/models/eft/common/IPmcData";
import { IBonus, IHideoutSlot } from "@spt/models/eft/common/tables/IBotBase";
import { IQuest, IQuestReward } from "@spt/models/eft/common/tables/IQuest";
import { IQuest } from "@spt/models/eft/common/tables/IQuest";
import { IReward } from "@spt/models/eft/common/tables/IReward";
import { IPmcDataRepeatableQuest, IRepeatableQuest } from "@spt/models/eft/common/tables/IRepeatableQuests";
import { ITemplateItem } from "@spt/models/eft/common/tables/ITemplateItem";
import { IStageBonus } from "@spt/models/eft/hideout/IHideoutArea";
@ -14,7 +15,7 @@ import { IEquipmentBuild, IMagazineBuild, ISptProfile, IWeaponBuild } from "@spt
import { BonusType } from "@spt/models/enums/BonusType";
import { ConfigTypes } from "@spt/models/enums/ConfigTypes";
import { HideoutAreas } from "@spt/models/enums/HideoutAreas";
import { QuestRewardType } from "@spt/models/enums/QuestRewardType";
import { RewardType } from "@spt/models/enums/RewardType";
import { QuestStatus } from "@spt/models/enums/QuestStatus";
import { ICoreConfig } from "@spt/models/spt/config/ICoreConfig";
import { IRagfairConfig } from "@spt/models/spt/config/IRagfairConfig";
@ -325,7 +326,7 @@ export class ProfileFixerService {
// For started or successful quests, check for unlocks in the `Started` rewards
if (profileQuest.status === QuestStatus.Started || profileQuest.status === QuestStatus.Success) {
const productionRewards = quest.rewards.Started?.filter(
(reward) => reward.type === QuestRewardType.PRODUCTIONS_SCHEME,
(reward) => reward.type === RewardType.PRODUCTIONS_SCHEME,
);
if (productionRewards) {
@ -338,7 +339,7 @@ export class ProfileFixerService {
// For successful quests, check for unlocks in the `Success` rewards
if (profileQuest.status === QuestStatus.Success) {
const productionRewards = quest.rewards.Success?.filter(
(reward) => reward.type === QuestRewardType.PRODUCTIONS_SCHEME,
(reward) => reward.type === RewardType.PRODUCTIONS_SCHEME,
);
if (productionRewards) {
@ -361,7 +362,7 @@ export class ProfileFixerService {
*/
protected verifyQuestProductionUnlock(
pmcProfile: IPmcData,
productionUnlockReward: IQuestReward,
productionUnlockReward: IReward,
questDetails: IQuest,
): void {
const matchingProductions = this.questRewardHelper.getRewardProductionMatch(

View File

@ -13,7 +13,7 @@
import * as path from "node:path";
import { OnLoad } from "@spt/di/OnLoad";
import { IHideoutProduction, IRequirement } from "@spt/models/eft/hideout/IHideoutProduction";
import { QuestRewardType } from "@spt/models/enums/QuestRewardType";
import { RewardType } from "@spt/models/enums/RewardType";
import type { ILogger } from "@spt/models/spt/utils/ILogger";
import { DatabaseServer } from "@spt/servers/DatabaseServer";
import { FileSystemSync } from "@spt/utils/FileSystemSync";
@ -129,7 +129,7 @@ export class ProductionQuestsGen {
for (const quest of Object.values(this.databaseServer.getTables().templates.quests)) {
for (const rewardState of Object.values(quest.rewards)) {
for (const reward of rewardState) {
if (reward.type !== QuestRewardType.PRODUCTIONS_SCHEME) continue;
if (reward.type !== RewardType.PRODUCTIONS_SCHEME) continue;
// Make the assumption all productions only output a single item template
const output: QuestProductionOutput = {