Add ability for repeatable quests to reward skill points

Slightly increase rep gain from weekly quests
This commit is contained in:
Dev 2023-11-07 14:38:13 +00:00
parent 5a60e4dcf0
commit 7defca2ae4
3 changed files with 61 additions and 16 deletions

View File

@ -148,7 +148,9 @@
"roubles": [15000, 40000, 75000, 100000, 140000, 170000, 210000], "roubles": [15000, 40000, 75000, 100000, 140000, 170000, 210000],
"items": [4, 4, 5, 5, 5, 6, 6], "items": [4, 4, 5, 5, 5, 6, 6],
"reputation": [0.01, 0.01, 0.02, 0.02], "reputation": [0.01, 0.01, 0.02, 0.02],
"rewardSpread": 0.5 "rewardSpread": 0.5,
"skillRewardChance": [0, 0.01, 0.05, 0.1, 0.15, 0.2, 0.25],
"skillPointReward": [10, 15, 20, 25, 30, 35, 40]
}, },
"locations": { "locations": {
"any": ["any"], "any": ["any"],
@ -188,6 +190,7 @@
"questConfig": { "questConfig": {
"Exploration": { "Exploration": {
"maxExtracts": 3, "maxExtracts": 3,
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"specificExits": { "specificExits": {
"probability": 0.25, "probability": 0.25,
"passageRequirementWhitelist": [ "passageRequirementWhitelist": [
@ -201,6 +204,7 @@
} }
}, },
"Completion": { "Completion": {
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"minRequestedAmount": 1, "minRequestedAmount": 1,
"maxRequestedAmount": 5, "maxRequestedAmount": 5,
"minRequestedBulletAmount": 20, "minRequestedBulletAmount": 20,
@ -213,6 +217,7 @@
"min": 1, "min": 1,
"max": 15 "max": 15
}, },
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"targets": [{ "targets": [{
"key": "Savage", "key": "Savage",
"relativeProbability": 1, "relativeProbability": 1,
@ -326,6 +331,7 @@
"min": 16, "min": 16,
"max": 40 "max": 40
}, },
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"targets": [{ "targets": [{
"key": "Savage", "key": "Savage",
"relativeProbability": 9, "relativeProbability": 9,
@ -507,6 +513,7 @@
"min": 41, "min": 41,
"max": 100 "max": 100
}, },
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"targets": [{ "targets": [{
"key": "Savage", "key": "Savage",
"relativeProbability": 9, "relativeProbability": 9,
@ -705,8 +712,10 @@
"experience": [5000, 25000, 60000, 130000, 240000, 390000, 750000], "experience": [5000, 25000, 60000, 130000, 240000, 390000, 750000],
"roubles": [50000, 150000, 300000, 425000, 550000, 675000, 850000], "roubles": [50000, 150000, 300000, 425000, 550000, 675000, 850000],
"items": [5, 5, 5, 6, 6, 7, 7], "items": [5, 5, 5, 6, 6, 7, 7],
"reputation": [0.02, 0.02, 0.03, 0.03, 0.03, 0.03, 0.03], "reputation": [0.02, 0.02, 0.03, 0.03, 0.04, 0.05, 0.05],
"rewardSpread": 0.5 "rewardSpread": 0.5,
"skillRewardChance": [0, 0.05, 0.1, 0.2, 0.3, 0.35, 0.4],
"skillPointReward": [20, 35, 40, 45, 50, 55, 60]
}, },
"locations": { "locations": {
"any": ["any"], "any": ["any"],
@ -745,6 +754,7 @@
], ],
"questConfig": { "questConfig": {
"Exploration": { "Exploration": {
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"maxExtracts": 10, "maxExtracts": 10,
"specificExits": { "specificExits": {
"probability": 0.4, "probability": 0.4,
@ -759,6 +769,7 @@
} }
}, },
"Completion": { "Completion": {
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"minRequestedAmount": 2, "minRequestedAmount": 2,
"maxRequestedAmount": 10, "maxRequestedAmount": 10,
"minRequestedBulletAmount": 20, "minRequestedBulletAmount": 20,
@ -771,6 +782,7 @@
"min": 1, "min": 1,
"max": 15 "max": 15
}, },
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"targets": [{ "targets": [{
"key": "Savage", "key": "Savage",
"relativeProbability": 15, "relativeProbability": 15,
@ -951,6 +963,7 @@
"min": 16, "min": 16,
"max": 40 "max": 40
}, },
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"targets": [{ "targets": [{
"key": "Savage", "key": "Savage",
"relativeProbability": 7, "relativeProbability": 7,
@ -1131,6 +1144,7 @@
"min": 41, "min": 41,
"max": 100 "max": 100
}, },
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"targets": [{ "targets": [{
"key": "Savage", "key": "Savage",
"relativeProbability": 7, "relativeProbability": 7,
@ -1331,7 +1345,9 @@
"roubles": [6000, 10000, 100000, 250000], "roubles": [6000, 10000, 100000, 250000],
"items": [2, 3, 4, 4], "items": [2, 3, 4, 4],
"reputation": [0.01, 0.02, 0.05, 0.05], "reputation": [0.01, 0.02, 0.05, 0.05],
"rewardSpread": 0.5 "rewardSpread": 0.5,
"skillRewardChance": [0, 0, 0, 0, 0, 0, 0],
"skillPointReward": [10, 15, 20, 25, 30, 35, 40]
}, },
"locations": { "locations": {
"any": ["any"], "any": ["any"],
@ -1351,6 +1367,7 @@
], ],
"questConfig": { "questConfig": {
"Exploration": { "Exploration": {
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"maxExtracts": 3, "maxExtracts": 3,
"specificExits": { "specificExits": {
"probability": 0.25, "probability": 0.25,
@ -1364,6 +1381,7 @@
} }
}, },
"Pickup": { "Pickup": {
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"ItemTypeToFetchWithMaxCount": [{ "ItemTypeToFetchWithMaxCount": [{
"itemType": "5b47574386f77428ca22b335", "itemType": "5b47574386f77428ca22b335",
"minPickupCount": 2, "minPickupCount": 2,
@ -1410,6 +1428,7 @@
"maxItemFetchCount": 3 "maxItemFetchCount": 3
}, },
"Completion": { "Completion": {
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"minRequestedAmount": 1, "minRequestedAmount": 1,
"maxRequestedAmount": 5, "maxRequestedAmount": 5,
"minRequestedBulletAmount": 20, "minRequestedBulletAmount": 20,
@ -1422,6 +1441,7 @@
"min": 1, "min": 1,
"max": 15 "max": 15
}, },
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"targets": "targets":
[{ [{
"key": "AnyPmc", "key": "AnyPmc",
@ -1460,7 +1480,7 @@
"minKills": 1, "minKills": 1,
"maxBossKills": 1, "maxBossKills": 1,
"minBossKills": 1, "minBossKills": 1,
"maxPmcKills": 2, "maxPmcKills": 2,
"minPmcKills": 1, "minPmcKills": 1,
"weaponRequirementProb": 0, "weaponRequirementProb": 0,
"weaponCategoryRequirementProb": 0.3, "weaponCategoryRequirementProb": 0.3,
@ -1537,6 +1557,7 @@
"min": 16, "min": 16,
"max": 100 "max": 100
}, },
"possibleSkillRewards": ["Endurance", "Strength", "Vitality"],
"targets": "targets":
[{ [{
"key": "AnyPmc", "key": "AnyPmc",
@ -1575,7 +1596,7 @@
"minKills": 3, "minKills": 3,
"maxBossKills": 3, "maxBossKills": 3,
"minBossKills": 1, "minBossKills": 1,
"maxPmcKills": 5, "maxPmcKills": 5,
"minPmcKills": 2, "minPmcKills": 2,
"weaponRequirementProb": 0, "weaponRequirementProb": 0,
"weaponCategoryRequirementProb": 0.3, "weaponCategoryRequirementProb": 0.3,

View File

@ -24,7 +24,7 @@ import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes"; import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
import { Money } from "@spt-aki/models/enums/Money"; import { Money } from "@spt-aki/models/enums/Money";
import { Traders } from "@spt-aki/models/enums/Traders"; import { Traders } from "@spt-aki/models/enums/Traders";
import { IBossInfo, IEliminationConfig, IQuestConfig, IRepeatableQuestConfig } from "@spt-aki/models/spt/config/IQuestConfig"; import { IBaseQuestConfig, IBossInfo, IEliminationConfig, IQuestConfig, IRepeatableQuestConfig } from "@spt-aki/models/spt/config/IQuestConfig";
import { IQuestTypePool } from "@spt-aki/models/spt/repeatable/IQuestTypePool"; import { IQuestTypePool } from "@spt-aki/models/spt/repeatable/IQuestTypePool";
import { ILogger } from "@spt-aki/models/spt/utils/ILogger"; import { ILogger } from "@spt-aki/models/spt/utils/ILogger";
import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder"; import { EventOutputHolder } from "@spt-aki/routers/EventOutputHolder";
@ -326,7 +326,7 @@ export class RepeatableQuestGenerator
availableForFinishCondition._props.id = this.objectId.generate(); availableForFinishCondition._props.id = this.objectId.generate();
quest.location = this.getQuestLocationByMapId(locationKey); quest.location = this.getQuestLocationByMapId(locationKey);
quest.rewards = this.generateReward(pmcLevel, Math.min(difficulty, 1), traderId, repeatableConfig); quest.rewards = this.generateReward(pmcLevel, Math.min(difficulty, 1), traderId, repeatableConfig, eliminationConfig);
return quest; return quest;
} }
@ -544,7 +544,7 @@ export class RepeatableQuestGenerator
} }
} }
quest.rewards = this.generateReward(pmcLevel, 1, traderId, repeatableConfig); quest.rewards = this.generateReward(pmcLevel, 1, traderId, repeatableConfig, completionConfig);
return quest; return quest;
} }
@ -673,7 +673,7 @@ export class RepeatableQuestGenerator
// Difficulty for exploration goes from 1 extract to maxExtracts // Difficulty for exploration goes from 1 extract to maxExtracts
// Difficulty for reward goes from 0.2...1 -> map // Difficulty for reward goes from 0.2...1 -> map
const difficulty = this.mathUtil.mapToRange(numExtracts, 1, explorationConfig.maxExtracts, 0.2, 1); const difficulty = this.mathUtil.mapToRange(numExtracts, 1, explorationConfig.maxExtracts, 0.2, 1);
quest.rewards = this.generateReward(pmcLevel, difficulty, traderId, repeatableConfig); quest.rewards = this.generateReward(pmcLevel, difficulty, traderId, repeatableConfig, explorationConfig);
return quest; return quest;
} }
@ -707,7 +707,7 @@ export class RepeatableQuestGenerator
(equipmentCondition._props as IEquipmentConditionProps).equipmentInclusive = [[itemTypeToFetchWithCount.itemType]]; (equipmentCondition._props as IEquipmentConditionProps).equipmentInclusive = [[itemTypeToFetchWithCount.itemType]];
// Add rewards // Add rewards
quest.rewards = this.generateReward(pmcLevel, 1, traderId, repeatableConfig); quest.rewards = this.generateReward(pmcLevel, 1, traderId, repeatableConfig, pickupConfig);
return quest; return quest;
} }
@ -765,7 +765,8 @@ export class RepeatableQuestGenerator
pmcLevel: number, pmcLevel: number,
difficulty: number, difficulty: number,
traderId: string, traderId: string,
repeatableConfig: IRepeatableQuestConfig repeatableConfig: IRepeatableQuestConfig,
questConfig: IBaseQuestConfig
): IRewards ): IRewards
{ {
// difficulty could go from 0.2 ... -> for lowest diffuculty receive 0.2*nominal reward // difficulty could go from 0.2 ... -> for lowest diffuculty receive 0.2*nominal reward
@ -774,6 +775,8 @@ export class RepeatableQuestGenerator
const xpConfig = repeatableConfig.rewardScaling.experience; const xpConfig = repeatableConfig.rewardScaling.experience;
const itemsConfig = repeatableConfig.rewardScaling.items; const itemsConfig = repeatableConfig.rewardScaling.items;
const rewardSpreadConfig = repeatableConfig.rewardScaling.rewardSpread; const rewardSpreadConfig = repeatableConfig.rewardScaling.rewardSpread;
const skillRewardChanceConfig = repeatableConfig.rewardScaling.skillRewardChance;
const skillPointRewardConfig = repeatableConfig.rewardScaling.skillPointReward;
const reputationConfig = repeatableConfig.rewardScaling.reputation; const reputationConfig = repeatableConfig.rewardScaling.reputation;
if (Number.isNaN(difficulty)) if (Number.isNaN(difficulty))
@ -788,6 +791,8 @@ export class RepeatableQuestGenerator
const rewardNumItems = this.randomUtil.randInt(1, Math.round(this.mathUtil.interp1(pmcLevel, levelsConfig, itemsConfig)) + 1); const rewardNumItems = this.randomUtil.randInt(1, Math.round(this.mathUtil.interp1(pmcLevel, levelsConfig, itemsConfig)) + 1);
const rewardReputation = Math.round(100 * difficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, reputationConfig) const rewardReputation = Math.round(100 * difficulty * this.mathUtil.interp1(pmcLevel, levelsConfig, reputationConfig)
* this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig)) / 100; * this.randomUtil.getFloat(1 - rewardSpreadConfig, 1 + rewardSpreadConfig)) / 100;
const skillRewardChance = this.mathUtil.interp1(pmcLevel, levelsConfig, skillRewardChanceConfig);
const skillPointReward = this.mathUtil.interp1(pmcLevel, levelsConfig, skillPointRewardConfig);
// Possible improvement -> draw trader-specific items e.g. with this.itemHelper.isOfBaseclass(val._id, ItemHelper.BASECLASS.FoodDrink) // Possible improvement -> draw trader-specific items e.g. with this.itemHelper.isOfBaseclass(val._id, ItemHelper.BASECLASS.FoodDrink)
let roublesBudget = rewardRoubles; let roublesBudget = rewardRoubles;
@ -879,6 +884,18 @@ export class RepeatableQuestGenerator
rewards.Success.push(reward); rewards.Success.push(reward);
} }
if (this.randomUtil.getChance100(skillRewardChance * 100))
{
index++;
const reward: IReward = {
target: this.randomUtil.getArrayValue(questConfig.possibleSkillRewards),
value: skillPointReward,
type: "Skill",
index: index
};
rewards.Success.push(reward);
}
return rewards; return rewards;
} }

View File

@ -68,6 +68,8 @@ export interface IRewardScaling
items: number[] items: number[]
reputation: number[] reputation: number[]
rewardSpread: number rewardSpread: number
skillRewardChance: number[]
skillPointReward: number[]
} }
export interface ITraderWhitelist export interface ITraderWhitelist
@ -84,7 +86,7 @@ export interface IRepeatableQuestTypesConfig
Elimination: IEliminationConfig[] Elimination: IEliminationConfig[]
} }
export interface IExploration export interface IExploration extends IBaseQuestConfig
{ {
maxExtracts: number maxExtracts: number
specificExits: ISpecificExits specificExits: ISpecificExits
@ -96,7 +98,7 @@ export interface ISpecificExits
passageRequirementWhitelist: string[] passageRequirementWhitelist: string[]
} }
export interface ICompletion export interface ICompletion extends IBaseQuestConfig
{ {
minRequestedAmount: number minRequestedAmount: number
maxRequestedAmount: number maxRequestedAmount: number
@ -106,7 +108,7 @@ export interface ICompletion
useBlacklist: boolean useBlacklist: boolean
} }
export interface IPickup export interface IPickup extends IBaseQuestConfig
{ {
ItemTypeToFetchWithMaxCount: IPickupTypeWithMaxCount[] ItemTypeToFetchWithMaxCount: IPickupTypeWithMaxCount[]
} }
@ -118,7 +120,7 @@ export interface IPickupTypeWithMaxCount
minPickupCount: number minPickupCount: number
} }
export interface IEliminationConfig export interface IEliminationConfig extends IBaseQuestConfig
{ {
levelRange: MinMax levelRange: MinMax
targets: ITarget[] targets: ITarget[]
@ -141,6 +143,11 @@ export interface IEliminationConfig
weaponRequirements: IWeaponRequirement[] weaponRequirements: IWeaponRequirement[]
} }
export interface IBaseQuestConfig
{
possibleSkillRewards: string[]
}
export interface ITarget extends IProbabilityObject export interface ITarget extends IProbabilityObject
{ {
data: IBossInfo data: IBossInfo