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

Implement Pickup quests for scav

It seems like these are scav-only
This commit is contained in:
Dev 2023-10-17 16:28:48 +01:00
parent e10b62a5b1
commit 650a3173c8
7 changed files with 235 additions and 12 deletions

View File

@ -11,7 +11,8 @@
"scav": {
"elimination": "62825ef60e88d037dc1eb428",
"completion": "628f588ebb558574b2260fe5",
"exploration": "62825ef60e88d037dc1eb42c"
"exploration": "62825ef60e88d037dc1eb42c",
"pickup": "628f588ebb558574b2260fe5"
}
},
"showNonSeasonalEventQuests": false,
@ -1297,8 +1298,10 @@
"name": "Daily_Savage",
"side": "Scav",
"types": [
"Exploration",
"Elimination",
"Completion"
"Completion",
"Pickup"
],
"resetTime": 86400,
"numQuests": 1,
@ -1324,7 +1327,7 @@
},
"traderWhitelist": [{
"traderId": "579dc571d53a0658a154fbec",
"questTypes": ["Completion", "Exploration", "Elimination"]
"questTypes": ["Completion", "Exploration", "Elimination", "Pickup"]
}
],
"questConfig": {
@ -1341,6 +1344,23 @@
]
}
},
"Pickup": {
"ItemTypeToFetchWithMaxCount": [
{"itemType": "5b47574386f77428ca22b335", "minPickupCount": 2, "maxPickupCount": 4},
{"itemType": "5b47574386f77428ca22b336", "minPickupCount": 2, "maxPickupCount": 4},
{"itemType": "5b47574386f77428ca22b2ee", "minPickupCount": 2, "maxPickupCount": 3},
{"itemType": "5b47574386f77428ca22b2ef", "minPickupCount": 1, "maxPickupCount": 2},
{"itemType": "5b47574386f77428ca22b33a", "minPickupCount": 1, "maxPickupCount": 2},
{"itemType": "5b5f701386f774093f2ecf0f", "minPickupCount": 1, "maxPickupCount": 2},
{"itemType": "5b5f754a86f774094242f19b", "minPickupCount": 1, "maxPickupCount": 3},
{"itemType": "5b5f75c686f774094242f19f", "minPickupCount": 1, "maxPickupCount": 2},
{"itemType": "5b5f792486f77447ed5636b3", "minPickupCount": 1, "maxPickupCount": 2},
{"itemType": "5b5f73ab86f774094242f195", "minPickupCount": 1, "maxPickupCount": 2},
{}
],
"ItemTypesToFetch": ["5b47574386f77428ca22b335", "5b47574386f77428ca22b336", "5b47574386f77428ca22b2ee"],
"maxItemFetchCount": 3
},
"Completion": {
"minRequestedAmount": 1,
"maxRequestedAmount": 5,

View File

@ -182,6 +182,110 @@
}
],
"changeStandingCost": 0
},
"Pickup": {
"_id": "64cfb3818db9f48b3f0b0a759",
"traderId": "579dc571d53a0658a154fbec",
"location": "any",
"image": "/files/quest/icon/62bd61b1b818ff064405b827.jpg",
"type": "PickUp",
"isKey": false,
"restartable": false,
"instantComplete": false,
"secretQuest": false,
"canShowNotificationsInGame": true,
"rewards": {
"Started": [],
"Success": [],
"Fail": []
},
"conditions": {
"AvailableForStart": [],
"AvailableForFinish": [{
"_props": {
"id": "64cfb3818db9f48b3f0b0a6f",
"parentId": "",
"dynamicLocale": false,
"index": 0,
"visibilityConditions": [],
"globalQuestCounterId": null,
"target": ["5b47574386f77428ca22b336"],
"value": 7,
"minDurability": 0,
"maxDurability": 100,
"dogtagLevel": 0,
"onlyFoundInRaid": false,
"isEncoded": false,
"countInRaid": true
},
"_parent": "FindItem",
"dynamicLocale": false
}, {
"_props": {
"id": "64cfb3818db9f48b3f0b0a74",
"parentId": "",
"dynamicLocale": true,
"index": 0,
"visibilityConditions": [],
"globalQuestCounterId": null,
"value": 1,
"type": "PickUp",
"completeInSeconds": 0,
"oneSessionOnly": true,
"doNotResetIfCounterCompleted": false,
"counter": {
"id": "64cfb3818db9f48b3f0b0a73",
"conditions": [{
"_props": {
"target": ["any"],
"id": "64cfb3818db9f48b3f0b0a70",
"dynamicLocale": true
},
"_parent": "Location"
}, {
"_props": {
"status": ["Survived"],
"id": "64cfb3818db9f48b3f0b0a71",
"dynamicLocale": true
},
"_parent": "ExitStatus"
}, {
"_props": {
"equipmentInclusive": [["5b47574386f77428ca22b336"]],
"IncludeNotEquippedItems": true,
"id": "64cfb3818db9f48b3f0b0a72",
"dynamicLocale": true
},
"_parent": "Equipment"
}
]
}
},
"_parent": "CounterCreator",
"dynamicLocale": true
}
],
"Fail": []
},
"side": "Scav",
"questStatus": {},
"name": "{templateId} name {traderId}",
"note": "{templateId} note {traderId}",
"description": "{templateId} description {traderId} 0",
"successMessageText": "{templateId} successMessageText {traderId} 0",
"failMessageText": "{templateId} failMessageText {traderId} 0",
"startedMessageText": "{templateId} startedMessageText {traderId} 0",
"changeQuestMessageText": "{templateId} changeQuestMessageText {traderId} 0",
"acceptPlayerMessage": "{templateId} acceptPlayerMessage {traderId}",
"declinePlayerMessage": "{templateId} declinePlayerMessage {traderId}",
"completePlayerMessage": "{templateId} completePlayerMessage {traderId}",
"templateId": "{templateId}",
"changeCost": [{
"templateId": "5449016a4bdc2d6f028b456f",
"count": 12000
}
],
"changeStandingCost": 0
}
},
"rewards": {

View File

@ -264,8 +264,13 @@ export class RepeatableQuestController
if (location !== ELocationName.ANY)
{
questPool.pool.Exploration.locations[location] = repeatableConfig.locations[location];
questPool.pool.Pickup.locations[location] = repeatableConfig.locations[location];
}
}
// Add "any" to pickup quest pool
questPool.pool.Pickup.locations["any"] = ["any"];
const eliminationConfig = this.repeatableQuestHelper.getEliminationConfigByPmcLevel(pmcLevel, repeatableConfig);
const targetsConfig = this.repeatableQuestHelper.probabilityObjectArray(eliminationConfig.targets);
for (const probabilityObject of targetsConfig)
@ -299,6 +304,9 @@ export class RepeatableQuestController
},
Elimination: {
targets: {}
},
Pickup: {
locations: {}
}
}
};

View File

@ -13,8 +13,10 @@ import {
ICompletionAvailableFor,
IElimination,
IEliminationCondition,
IEquipmentConditionProps,
IExploration,
IExplorationCondition, IKillConditionProps,
IPickup,
IRepeatableQuest, IReward, IRewards
} from "../models/eft/common/tables/IRepeatableQuests";
import { ITemplateItem } from "../models/eft/common/tables/ITemplateItem";
@ -104,6 +106,8 @@ export class RepeatableQuestGenerator
return this.generateCompletionQuest(pmcLevel, traderId, repeatableConfig);
case "Exploration":
return this.generateExplorationQuest(pmcLevel, traderId, questTypePool, repeatableConfig);
case "Pickup":
return this.generatePickupQuest(pmcLevel, traderId, questTypePool, repeatableConfig);
default:
throw new Error(`Unknown mission type ${questType}. Should never be here!`);
}
@ -304,7 +308,7 @@ export class RepeatableQuestGenerator
// crazy maximum difficulty will lead to a higher difficulty reward gain factor than 1
const difficulty = this.mathUtil.mapToRange(curDifficulty, minDifficulty, maxDifficulty, 0.5, 2);
const quest = this.generateRepeatableTemplate("Elimination", traderId,repeatableConfig.side) as IElimination;
const quest = this.generateRepeatableTemplate("Elimination", traderId, repeatableConfig.side) as IElimination;
// ASSUMPTION: All fence quests are for scavs
if (traderId === Traders.FENCE)
@ -312,15 +316,16 @@ export class RepeatableQuestGenerator
quest.side = "Scav";
}
quest.conditions.AvailableForFinish[0]._props.counter.id = this.objectId.generate();
quest.conditions.AvailableForFinish[0]._props.counter.conditions = [];
const availableForFinishCondition = quest.conditions.AvailableForFinish[0];
availableForFinishCondition._props.counter.id = this.objectId.generate();
availableForFinishCondition._props.counter.conditions = [];
if (locationKey !== "any")
{
quest.conditions.AvailableForFinish[0]._props.counter.conditions.push(this.generateEliminationLocation(locationsConfig[locationKey], allowedWeapon, allowedWeaponsCategory));
availableForFinishCondition._props.counter.conditions.push(this.generateEliminationLocation(locationsConfig[locationKey], allowedWeapon, allowedWeaponsCategory));
}
quest.conditions.AvailableForFinish[0]._props.counter.conditions.push(this.generateEliminationCondition(targetKey, bodyPartsToClient, distance, allowedWeapon, allowedWeaponsCategory));
quest.conditions.AvailableForFinish[0]._props.value = kills;
quest.conditions.AvailableForFinish[0]._props.id = this.objectId.generate();
availableForFinishCondition._props.counter.conditions.push(this.generateEliminationCondition(targetKey, bodyPartsToClient, distance, allowedWeapon, allowedWeaponsCategory));
availableForFinishCondition._props.value = kills;
availableForFinishCondition._props.id = this.objectId.generate();
quest.location = this.getQuestLocationByMapId(locationKey);
quest.rewards = this.generateReward(pmcLevel, Math.min(difficulty, 1), traderId, repeatableConfig);
@ -660,6 +665,40 @@ export class RepeatableQuestGenerator
return quest;
}
protected generatePickupQuest(
pmcLevel: number,
traderId: string,
questTypePool: IQuestTypePool,
repeatableConfig: IRepeatableQuestConfig
): IPickup
{
const pickupConfig = repeatableConfig.questConfig.Pickup;
const quest = this.generateRepeatableTemplate("Pickup", traderId, repeatableConfig.side) as IPickup;
const itemTypeToFetchWithCount = this.randomUtil.getArrayValue(pickupConfig.ItemTypeToFetchWithMaxCount);
const itemCountToFetch = this.randomUtil.randInt(itemTypeToFetchWithCount.minPickupCount, itemTypeToFetchWithCount.maxPickupCount + 1);
// Choose location - doesnt seem to work for anything other than 'any'
//const locationKey: string = this.randomUtil.drawRandomFromDict(questTypePool.pool.Pickup.locations)[0];
//const locationTarget = questTypePool.pool.Pickup.locations[locationKey];
const findCondition = quest.conditions.AvailableForFinish.find(x => x._parent === "FindItem");
findCondition._props.target = [itemTypeToFetchWithCount.itemType];
findCondition._props.value = itemCountToFetch;
const counterCreatorCondition = quest.conditions.AvailableForFinish.find(x => x._parent === "CounterCreator");
//const locationCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Location");
//(locationCondition._props as ILocationConditionProps).target = [...locationTarget];
const equipmentCondition = counterCreatorCondition._props.counter.conditions.find(x => x._parent === "Equipment");
(equipmentCondition._props as IEquipmentConditionProps).equipmentInclusive = [[itemTypeToFetchWithCount.itemType]];
// Add rewards
quest.rewards = this.generateReward(pmcLevel, 1, traderId, repeatableConfig);
return quest;
}
/**
* Convert a location into an quest code can read (e.g. factory4_day into 55f2d3fd4bdc2d5f408b4567)
* @param locationKey e.g factory4_day

View File

@ -119,7 +119,7 @@ export interface IAvailableForPropsCounter extends IAvailableForProps
type: string
oneSessionOnly: boolean
doNotResetIfCounterCompleted: boolean
counter: ICounter
counter?: ICounter
}
export interface ICounter
@ -204,6 +204,38 @@ export interface IExplorationCondition extends ICondition
_props: ILocationConditionProps | IExitStatusConditionProps | IExitNameConditionProps
}
// Pickup
export interface IPickup extends IRepeatableQuest
{
conditions: IPickupConditions
}
export interface IPickupConditions extends IConditions
{
AvailableForFinish: IPickupAvailableFor[]
}
export interface IPickupAvailableFor extends IAvailableFor
{
_props: IPickupAvailableForProps
}
export interface IPickupAvailableForProps extends IAvailableForPropsCounter
{
target: string[]
counter?: IPickupCounter
}
export interface IPickupCounter extends ICounter
{
conditions: IPickupCondition[]
}
export interface IPickupCondition extends ICondition
{
_props: IEquipmentConditionProps | ILocationConditionProps | IExitStatusConditionProps
}
// Completion
export interface ICompletion extends IRepeatableQuest
{
@ -238,6 +270,12 @@ export interface ILocationConditionProps extends IConditionProps
weaponCategories?: string[]
}
export interface IEquipmentConditionProps extends IConditionProps
{
equipmentInclusive: [string[]]
IncludeNotEquippedItems: boolean
}
export interface IKillConditionProps extends IConditionProps
{
target: string

View File

@ -79,6 +79,7 @@ export interface IRepeatableQuestTypesConfig
{
Exploration: IExploration
Completion: ICompletion
Pickup: IPickup;
Elimination: IEliminationConfig[]
}
@ -104,6 +105,18 @@ export interface ICompletion
useBlacklist: boolean
}
export interface IPickup
{
ItemTypeToFetchWithMaxCount: IPickupTypeWithMaxCount[]
}
export interface IPickupTypeWithMaxCount
{
itemType: string
maxPickupCount: number
minPickupCount: number
}
export interface IEliminationConfig
{
levelRange: MinMax

View File

@ -10,6 +10,7 @@ export interface IQuestPool
{
Exploration: IExplorationPool
Elimination: IEliminationPool
Pickup: IExplorationPool
}
export interface IExplorationPool