Updated server handling of quests/repeatable quests to match 0.14 changes - this will break profiles
This commit is contained in:
parent
3979e6ef61
commit
9dbd3d1acf
@ -19,39 +19,51 @@
|
||||
"conditions": {
|
||||
"AvailableForStart": [],
|
||||
"AvailableForFinish": [{
|
||||
"_props": {
|
||||
"id": "618c1de4d4cd91439f3de4ae",
|
||||
"parentId": "",
|
||||
"dynamicLocale": true,
|
||||
"index": 0,
|
||||
"visibilityConditions": [],
|
||||
"value": 1,
|
||||
"type": "Elimination",
|
||||
"oneSessionOnly": false,
|
||||
"doNotResetIfCounterCompleted": false,
|
||||
"counter": {
|
||||
"id": "618c1de4d4cd91439f3de4ac",
|
||||
"conditions": [{
|
||||
"_props": {
|
||||
"target": "Savage",
|
||||
"value": 1,
|
||||
"savageRole": [
|
||||
"bossBully"
|
||||
],
|
||||
"id": "618c1de4d4cd91439f3de4ad",
|
||||
"dynamicLocale": true
|
||||
},
|
||||
"_parent": "Kills"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"_parent": "CounterCreator",
|
||||
"dynamicLocale": true
|
||||
}
|
||||
],
|
||||
"id": "618c1de4d4cd91439f3de4ae",
|
||||
"index": 0,
|
||||
"dynamicLocale": true,
|
||||
"visibilityConditions": [],
|
||||
"globalQuestCounterId": "",
|
||||
"parentId": "",
|
||||
"value": 1,
|
||||
"type": "Elimination",
|
||||
"oneSessionOnly": false,
|
||||
"doNotResetIfCounterCompleted": false,
|
||||
"counter": {
|
||||
"id": "618c1de4d4cd91439f3de4ac",
|
||||
"conditions": [{
|
||||
"id": "618c1de4d4cd91439f3de4ad",
|
||||
"dynamicLocale": true,
|
||||
"target": "Savage",
|
||||
"compareMethod": ">=",
|
||||
"value": 1,
|
||||
"weapon": [],
|
||||
"distance": {
|
||||
"value": 0,
|
||||
"compareMethod": ">="
|
||||
},
|
||||
"weaponModsInclusive": [],
|
||||
"weaponModsExclusive": [],
|
||||
"enemyEquipmentInclusive": [],
|
||||
"enemyEquipmentExclusive": [],
|
||||
"weaponCaliber": [],
|
||||
"savageRole": [],
|
||||
"bodyPart": [],
|
||||
"daytime": {
|
||||
"from": 0,
|
||||
"to": 0
|
||||
},
|
||||
"enemyHealthEffects": [],
|
||||
"resetOnSessionEnd": false,
|
||||
"conditionType": "Kills"
|
||||
}
|
||||
]
|
||||
},
|
||||
"conditionType": "CounterCreator"
|
||||
}],
|
||||
"Fail": []
|
||||
},
|
||||
"side": "Pmc",
|
||||
"name": "{templateId} name {traderId}",
|
||||
"note": "{templateId} note {traderId}",
|
||||
"description": "{templateId} description {traderId} 0",
|
||||
@ -91,6 +103,7 @@
|
||||
"AvailableForFinish": [],
|
||||
"Fail": []
|
||||
},
|
||||
"side": "Pmc",
|
||||
"name": "{templateId} name {traderId}",
|
||||
"note": "{templateId} note {traderId}",
|
||||
"description": "{templateId} description {traderId} 0",
|
||||
@ -110,7 +123,7 @@
|
||||
"changeStandingCost": 0
|
||||
},
|
||||
"Exploration": {
|
||||
"_id": null,
|
||||
"_id": "65947c6afb90e7fcb40f8d684",
|
||||
"traderId": "54cb50c76803fa8b248b4571",
|
||||
"location": null,
|
||||
"image": "/files/quest/icon/616d993bc8c5ad2ab30ff6ba.jpg",
|
||||
@ -128,44 +141,40 @@
|
||||
"conditions": {
|
||||
"AvailableForStart": [],
|
||||
"AvailableForFinish": [{
|
||||
"_props": {
|
||||
"id": "618c1de4d4cd91439f3de4a5",
|
||||
"parentId": "",
|
||||
"dynamicLocale": true,
|
||||
"index": 0,
|
||||
"visibilityConditions": [],
|
||||
"value": 1,
|
||||
"type": "Completion",
|
||||
"oneSessionOnly": false,
|
||||
"doNotResetIfCounterCompleted": false,
|
||||
"counter": {
|
||||
"id": "618c1de4d4cd91439f3de4a4",
|
||||
"conditions": [{
|
||||
"_props": {
|
||||
"status": [
|
||||
"Survived"
|
||||
],
|
||||
"id": "618c1de4d4cd91439f3de4a3",
|
||||
"dynamicLocale": true
|
||||
},
|
||||
"_parent": "ExitStatus"
|
||||
}, {
|
||||
"_props": {
|
||||
"target": [],
|
||||
"id": "618c1de4d4cd91439f3de4a2",
|
||||
"dynamicLocale": true
|
||||
},
|
||||
"_parent": "Location"
|
||||
}
|
||||
]
|
||||
}
|
||||
},
|
||||
"_parent": "CounterCreator",
|
||||
"dynamicLocale": true
|
||||
"id": "618c1de4d4cd91439f3de4a5",
|
||||
"index": 0,
|
||||
"dynamicLocale": true,
|
||||
"visibilityConditions": [],
|
||||
"globalQuestCounterId": "",
|
||||
"parentId": "",
|
||||
"value": 1,
|
||||
"type": "Completion",
|
||||
"oneSessionOnly": false,
|
||||
"completeInSeconds": 0,
|
||||
"doNotResetIfCounterCompleted": false,
|
||||
"counter": {
|
||||
"id": "618c1de4d4cd91439f3de4a4",
|
||||
"conditions": [{
|
||||
"status": [
|
||||
"Survived"
|
||||
],
|
||||
"id": "618c1de4d4cd91439f3de4a3",
|
||||
"dynamicLocale": true,
|
||||
"conditionType": "ExitStatus"
|
||||
}, {
|
||||
"target": [],
|
||||
"id": "618c1de4d4cd91439f3de4a2",
|
||||
"dynamicLocale": true,
|
||||
"conditionType": "Location"
|
||||
}
|
||||
]
|
||||
},
|
||||
"conditionType": "CounterCreator"
|
||||
}
|
||||
],
|
||||
"Fail": []
|
||||
},
|
||||
"side": "Pmc",
|
||||
"name": "{templateId} name {traderId}",
|
||||
"note": "{templateId} note {traderId}",
|
||||
"description": "{templateId} description {traderId} 0",
|
||||
@ -203,73 +212,60 @@
|
||||
"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
|
||||
"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,
|
||||
"conditionType": "FindItem"
|
||||
}, {
|
||||
"_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
|
||||
"id": "64cfb3818db9f48b3f0b0a74",
|
||||
"parentId": "",
|
||||
"dynamicLocale": true,
|
||||
"index": 0,
|
||||
"visibilityConditions": [],
|
||||
"globalQuestCounterId": null,
|
||||
"value": 1,
|
||||
"type": "PickUp",
|
||||
"completeInSeconds": 0,
|
||||
"oneSessionOnly": true,
|
||||
"doNotResetIfCounterCompleted": false,
|
||||
"counter": {
|
||||
"id": "64cfb3818db9f48b3f0b0a73",
|
||||
"conditions": [{
|
||||
"target": ["any"],
|
||||
"id": "64cfb3818db9f48b3f0b0a70",
|
||||
"dynamicLocale": true,
|
||||
"conditionType": "Location"
|
||||
}, {
|
||||
"status": ["Survived"],
|
||||
"id": "64cfb3818db9f48b3f0b0a71",
|
||||
"dynamicLocale": true,
|
||||
"conditionType": "ExitStatus"
|
||||
}, {
|
||||
"equipmentInclusive": [["5b47574386f77428ca22b336"]],
|
||||
"IncludeNotEquippedItems": true,
|
||||
"id": "64cfb3818db9f48b3f0b0a72",
|
||||
"dynamicLocale": true,
|
||||
"conditionType": "Equipment"
|
||||
}
|
||||
]
|
||||
},
|
||||
"conditionType": "CounterCreator"
|
||||
}
|
||||
],
|
||||
"Fail": []
|
||||
},
|
||||
"side": "Scav",
|
||||
"questStatus": {},
|
||||
"name": "{templateId} name {traderId}",
|
||||
"note": "{templateId} note {traderId}",
|
||||
"description": "{templateId} description {traderId} 0",
|
||||
|
@ -9,7 +9,7 @@ import { TraderHelper } from "@spt-aki/helpers/TraderHelper";
|
||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||
import { IQuestStatus } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
import { AvailableForConditions, IQuest, Reward } from "@spt-aki/models/eft/common/tables/IQuest";
|
||||
import { IQuest, IQuestCondition } from "@spt-aki/models/eft/common/tables/IQuest";
|
||||
import { IPmcDataRepeatableQuest, IRepeatableQuest } from "@spt-aki/models/eft/common/tables/IRepeatableQuests";
|
||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||
import { IAcceptQuestRequestData } from "@spt-aki/models/eft/quests/IAcceptQuestRequestData";
|
||||
@ -135,7 +135,7 @@ export class QuestController
|
||||
for (const conditionToFulfil of questRequirements)
|
||||
{
|
||||
// If the previous quest isn't in the user profile, it hasn't been completed or started
|
||||
const prerequisiteQuest = profile.Quests.find((pq) => pq.qid === conditionToFulfil.target);
|
||||
const prerequisiteQuest = profile.Quests.find((profileQuest) => conditionToFulfil.target.includes(profileQuest.qid));
|
||||
if (!prerequisiteQuest)
|
||||
{
|
||||
haveCompletedPreviousQuest = false;
|
||||
@ -609,7 +609,7 @@ export class QuestController
|
||||
sessionID: string,
|
||||
pmcData: IPmcData,
|
||||
completedQuestId: string,
|
||||
questRewards: Reward[],
|
||||
questRewards: Item[],
|
||||
): void
|
||||
{
|
||||
const quest = this.questHelper.getQuestFromDb(completedQuestId, pmcData);
|
||||
@ -637,7 +637,7 @@ export class QuestController
|
||||
{
|
||||
// If quest has prereq of completed quest + availableAfter value > 0 (quest has wait time)
|
||||
const nextQuestWaitCondition = quest.conditions.AvailableForStart.find((x) =>
|
||||
x.target === completedQuestId && x.availableAfter > 0
|
||||
x.target.includes(completedQuestId) && x.availableAfter > 0
|
||||
);
|
||||
if (nextQuestWaitCondition)
|
||||
{
|
||||
@ -687,7 +687,7 @@ export class QuestController
|
||||
return false;
|
||||
}
|
||||
|
||||
return x.conditions.Fail.some((y) => y.target === completedQuestId);
|
||||
return x.conditions.Fail.some((y) => y.target.includes(completedQuestId));
|
||||
});
|
||||
}
|
||||
|
||||
@ -760,7 +760,7 @@ export class QuestController
|
||||
let handedInCount = 0;
|
||||
|
||||
// Decrement number of items handed in
|
||||
let handoverRequirements: AvailableForConditions;
|
||||
let handoverRequirements: IQuestCondition;
|
||||
for (const condition of quest.conditions.AvailableForFinish)
|
||||
{
|
||||
if (
|
||||
@ -897,7 +897,7 @@ export class QuestController
|
||||
protected showQuestItemHandoverMatchError(
|
||||
handoverQuestRequest: IHandoverQuestRequestData,
|
||||
itemHandedOver: Item,
|
||||
handoverRequirements: AvailableForConditions,
|
||||
handoverRequirements: IQuestCondition,
|
||||
output: IItemEventRouterResponse,
|
||||
): IItemEventRouterResponse
|
||||
{
|
||||
|
@ -182,7 +182,7 @@ export class RepeatableQuestController
|
||||
}
|
||||
}
|
||||
|
||||
// create stupid redundant change requirements from quest data
|
||||
// Create stupid redundant change requirements from quest data
|
||||
for (const quest of currentRepeatableQuestType.activeQuests)
|
||||
{
|
||||
currentRepeatableQuestType.changeRequirement[quest._id] = {
|
||||
|
@ -9,24 +9,13 @@ import { RepeatableQuestHelper } from "@spt-aki/helpers/RepeatableQuestHelper";
|
||||
import { Exit, ILocationBase } from "@spt-aki/models/eft/common/ILocationBase";
|
||||
import { TraderInfo } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
import {
|
||||
ICompletion,
|
||||
ICompletionAvailableFor,
|
||||
IElimination,
|
||||
IEliminationCondition,
|
||||
IEquipmentConditionProps,
|
||||
IExploration,
|
||||
IExplorationCondition,
|
||||
IKillConditionProps,
|
||||
IPickup,
|
||||
IRepeatableQuest,
|
||||
IReward,
|
||||
IRewards,
|
||||
} from "@spt-aki/models/eft/common/tables/IRepeatableQuests";
|
||||
import { IQuestCondition, IQuestConditionCounterCondition, IQuestReward, IQuestRewards } from "@spt-aki/models/eft/common/tables/IQuest";
|
||||
import { IRepeatableQuest } from "@spt-aki/models/eft/common/tables/IRepeatableQuests";
|
||||
import { ITemplateItem } from "@spt-aki/models/eft/common/tables/ITemplateItem";
|
||||
import { BaseClasses } from "@spt-aki/models/enums/BaseClasses";
|
||||
import { ConfigTypes } from "@spt-aki/models/enums/ConfigTypes";
|
||||
import { Money } from "@spt-aki/models/enums/Money";
|
||||
import { QuestRewardType } from "@spt-aki/models/enums/QuestRewardType";
|
||||
import { Traders } from "@spt-aki/models/enums/Traders";
|
||||
import {
|
||||
IBaseQuestConfig,
|
||||
@ -136,7 +125,7 @@ export class RepeatableQuestGenerator
|
||||
traderId: string,
|
||||
questTypePool: IQuestTypePool,
|
||||
repeatableConfig: IRepeatableQuestConfig,
|
||||
): IElimination
|
||||
): IRepeatableQuest
|
||||
{
|
||||
const eliminationConfig = this.repeatableQuestHelper.getEliminationConfigByPmcLevel(pmcLevel, repeatableConfig);
|
||||
const locationsConfig = repeatableConfig.locations;
|
||||
@ -337,7 +326,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);
|
||||
|
||||
// ASSUMPTION: All fence quests are for scavs
|
||||
if (traderId === Traders.FENCE)
|
||||
@ -346,17 +335,17 @@ export class RepeatableQuestGenerator
|
||||
}
|
||||
|
||||
const availableForFinishCondition = quest.conditions.AvailableForFinish[0];
|
||||
availableForFinishCondition._props.counter.id = this.objectId.generate();
|
||||
availableForFinishCondition._props.counter.conditions = [];
|
||||
availableForFinishCondition.counter.id = this.objectId.generate();
|
||||
availableForFinishCondition.counter.conditions = [];
|
||||
|
||||
// Only add specific location condition if specific map selected
|
||||
if (locationKey !== "any")
|
||||
{
|
||||
availableForFinishCondition._props.counter.conditions.push(
|
||||
availableForFinishCondition.counter.conditions.push(
|
||||
this.generateEliminationLocation(locationsConfig[locationKey]),
|
||||
);
|
||||
}
|
||||
availableForFinishCondition._props.counter.conditions.push(
|
||||
availableForFinishCondition.counter.conditions.push(
|
||||
this.generateEliminationCondition(
|
||||
targetKey,
|
||||
bodyPartsToClient,
|
||||
@ -365,8 +354,8 @@ export class RepeatableQuestGenerator
|
||||
allowedWeaponsCategory,
|
||||
),
|
||||
);
|
||||
availableForFinishCondition._props.value = desiredKillCount;
|
||||
availableForFinishCondition._props.id = this.objectId.generate();
|
||||
availableForFinishCondition.value = desiredKillCount;
|
||||
availableForFinishCondition.id = this.objectId.generate();
|
||||
quest.location = this.getQuestLocationByMapId(locationKey);
|
||||
|
||||
quest.rewards = this.generateReward(
|
||||
@ -413,11 +402,13 @@ export class RepeatableQuestGenerator
|
||||
* @param {string} location the location on which to fulfill the elimination quest
|
||||
* @returns {IEliminationCondition} object of "Elimination"-location-subcondition
|
||||
*/
|
||||
protected generateEliminationLocation(location: string[]): IEliminationCondition
|
||||
protected generateEliminationLocation(location: string[]): IQuestConditionCounterCondition
|
||||
{
|
||||
const propsObject: IEliminationCondition = {
|
||||
_props: { target: location, id: this.objectId.generate(), dynamicLocale: true },
|
||||
_parent: "Location",
|
||||
const propsObject: IQuestConditionCounterCondition = {
|
||||
id: this.objectId.generate(),
|
||||
dynamicLocale: true,
|
||||
target: location,
|
||||
conditionType: "Location"
|
||||
};
|
||||
|
||||
return propsObject;
|
||||
@ -438,13 +429,14 @@ export class RepeatableQuestGenerator
|
||||
distance: number,
|
||||
allowedWeapon: string,
|
||||
allowedWeaponCategory: string,
|
||||
): IEliminationCondition
|
||||
): IQuestConditionCounterCondition
|
||||
{
|
||||
const killConditionProps: IKillConditionProps = {
|
||||
const killConditionProps: IQuestConditionCounterCondition = {
|
||||
target: target,
|
||||
value: 1,
|
||||
id: this.objectId.generate(),
|
||||
dynamicLocale: true,
|
||||
conditionType: "Kills",
|
||||
};
|
||||
|
||||
if (target.startsWith("boss"))
|
||||
@ -474,10 +466,11 @@ export class RepeatableQuestGenerator
|
||||
// Has specific weapon category requirement
|
||||
if (allowedWeaponCategory?.length > 0)
|
||||
{
|
||||
killConditionProps.weaponCategories = [allowedWeaponCategory];
|
||||
// TODO - fix - does weaponCategories exist?
|
||||
//killConditionProps.weaponCategories = [allowedWeaponCategory];
|
||||
}
|
||||
|
||||
return { _props: killConditionProps, _parent: "Kills" };
|
||||
return killConditionProps;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -492,7 +485,7 @@ export class RepeatableQuestGenerator
|
||||
pmcLevel: number,
|
||||
traderId: string,
|
||||
repeatableConfig: IRepeatableQuestConfig,
|
||||
): ICompletion
|
||||
): IRepeatableQuest
|
||||
{
|
||||
const completionConfig = repeatableConfig.questConfig.Completion;
|
||||
const levelsConfig = repeatableConfig.rewardScaling.levels;
|
||||
@ -500,7 +493,7 @@ export class RepeatableQuestGenerator
|
||||
|
||||
const distinctItemsToRetrieveCount = this.randomUtil.getInt(1, completionConfig.uniqueItemCount);
|
||||
|
||||
const quest = this.generateRepeatableTemplate("Completion", traderId, repeatableConfig.side) as ICompletion;
|
||||
const quest = this.generateRepeatableTemplate("Completion", traderId, repeatableConfig.side);
|
||||
|
||||
// Filter the items.json items to items the player must retrieve to complete quest: shouldn't be a quest item or "non-existant"
|
||||
const possibleItemsToRetrievePool = this.getRewardableItems(repeatableConfig, traderId);
|
||||
@ -628,7 +621,7 @@ export class RepeatableQuestGenerator
|
||||
* @param {integer} value amount of items of this specific type to request
|
||||
* @returns {object} object of "Completion"-condition
|
||||
*/
|
||||
protected generateCompletionAvailableForFinish(itemTpl: string, value: number): ICompletionAvailableFor
|
||||
protected generateCompletionAvailableForFinish(itemTpl: string, value: number): IQuestCondition
|
||||
{
|
||||
let minDurability = 0;
|
||||
let onlyFoundInRaid = true;
|
||||
@ -650,21 +643,18 @@ export class RepeatableQuestGenerator
|
||||
}
|
||||
|
||||
return {
|
||||
_props: {
|
||||
id: this.objectId.generate(),
|
||||
parentId: "",
|
||||
dynamicLocale: true,
|
||||
index: 0,
|
||||
visibilityConditions: [],
|
||||
target: [itemTpl],
|
||||
value: value,
|
||||
minDurability: minDurability,
|
||||
maxDurability: 100,
|
||||
dogtagLevel: 0,
|
||||
onlyFoundInRaid: onlyFoundInRaid,
|
||||
},
|
||||
_parent: "HandoverItem",
|
||||
id: this.objectId.generate(),
|
||||
parentId: "",
|
||||
dynamicLocale: true,
|
||||
index: 0,
|
||||
visibilityConditions: [],
|
||||
target: [itemTpl],
|
||||
value: value,
|
||||
minDurability: minDurability,
|
||||
maxDurability: 100,
|
||||
dogtagLevel: 0,
|
||||
onlyFoundInRaid: onlyFoundInRaid,
|
||||
conditionType: "HandoverItem",
|
||||
};
|
||||
}
|
||||
|
||||
@ -682,7 +672,7 @@ export class RepeatableQuestGenerator
|
||||
traderId: string,
|
||||
questTypePool: IQuestTypePool,
|
||||
repeatableConfig: IRepeatableQuestConfig,
|
||||
): IExploration
|
||||
): IRepeatableQuest
|
||||
{
|
||||
const explorationConfig = repeatableConfig.questConfig.Exploration;
|
||||
const requiresSpecificExtract = Math.random() < repeatableConfig.questConfig.Exploration.specificExits.probability;
|
||||
@ -705,24 +695,27 @@ export class RepeatableQuestGenerator
|
||||
// Different max extract count when specific extract needed
|
||||
const numExtracts = this.randomUtil.randInt(1, requiresSpecificExtract ? explorationConfig.maxExtractsWithSpecificExit : explorationConfig.maxExtracts + 1);
|
||||
|
||||
const quest = this.generateRepeatableTemplate("Exploration", traderId, repeatableConfig.side) as IExploration;
|
||||
const quest = this.generateRepeatableTemplate("Exploration", traderId, repeatableConfig.side);
|
||||
|
||||
const exitStatusCondition: IExplorationCondition = {
|
||||
_parent: "ExitStatus",
|
||||
_props: { id: this.objectId.generate(), dynamicLocale: true, status: ["Survived"] },
|
||||
const exitStatusCondition: IQuestConditionCounterCondition = {
|
||||
conditionType: "ExitStatus",
|
||||
id: this.objectId.generate(),
|
||||
dynamicLocale: true,
|
||||
status: ["Survived"],
|
||||
};
|
||||
const locationCondition: IExplorationCondition = {
|
||||
_parent: "Location",
|
||||
_props: { id: this.objectId.generate(), dynamicLocale: true, target: locationTarget },
|
||||
const locationCondition: IQuestConditionCounterCondition = {
|
||||
conditionType: "Location",
|
||||
id: this.objectId.generate(),
|
||||
dynamicLocale: true,
|
||||
target: locationTarget,
|
||||
};
|
||||
|
||||
quest.conditions.AvailableForFinish[0]._props.counter.id = this.objectId.generate();
|
||||
quest.conditions.AvailableForFinish[0]._props.counter.conditions = [exitStatusCondition, locationCondition];
|
||||
quest.conditions.AvailableForFinish[0]._props.value = numExtracts;
|
||||
quest.conditions.AvailableForFinish[0]._props.id = this.objectId.generate();
|
||||
quest.conditions.AvailableForFinish[0].counter.id = this.objectId.generate();
|
||||
quest.conditions.AvailableForFinish[0].counter.conditions = [exitStatusCondition, locationCondition];
|
||||
quest.conditions.AvailableForFinish[0].value = numExtracts;
|
||||
quest.conditions.AvailableForFinish[0].id = this.objectId.generate();
|
||||
quest.location = this.getQuestLocationByMapId(locationKey);
|
||||
|
||||
|
||||
if (requiresSpecificExtract)
|
||||
{
|
||||
// Filter by whitelist, it's also possible that the field "PassageRequirement" does not exist (e.g. Shoreline)
|
||||
@ -737,7 +730,7 @@ export class RepeatableQuestGenerator
|
||||
);
|
||||
const exit = this.randomUtil.drawRandomFromList(possibleExists, 1)[0];
|
||||
const exitCondition = this.generateExplorationExitCondition(exit);
|
||||
quest.conditions.AvailableForFinish[0]._props.counter.conditions.push(exitCondition);
|
||||
quest.conditions.AvailableForFinish[0].counter.conditions.push(exitCondition);
|
||||
}
|
||||
|
||||
// Difficulty for exploration goes from 1 extract to maxExtracts
|
||||
@ -753,11 +746,11 @@ export class RepeatableQuestGenerator
|
||||
traderId: string,
|
||||
questTypePool: IQuestTypePool,
|
||||
repeatableConfig: IRepeatableQuestConfig,
|
||||
): IPickup
|
||||
): IRepeatableQuest
|
||||
{
|
||||
const pickupConfig = repeatableConfig.questConfig.Pickup;
|
||||
|
||||
const quest = this.generateRepeatableTemplate("Pickup", traderId, repeatableConfig.side) as IPickup;
|
||||
const quest = this.generateRepeatableTemplate("Pickup", traderId, repeatableConfig.side);
|
||||
|
||||
const itemTypeToFetchWithCount = this.randomUtil.getArrayValue(pickupConfig.ItemTypeToFetchWithMaxCount);
|
||||
const itemCountToFetch = this.randomUtil.randInt(
|
||||
@ -768,18 +761,18 @@ export class RepeatableQuestGenerator
|
||||
// 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 findCondition = quest.conditions.AvailableForFinish.find((x) => x.conditionType === "FindItem");
|
||||
findCondition.target = [itemTypeToFetchWithCount.itemType];
|
||||
findCondition.value = itemCountToFetch;
|
||||
|
||||
const counterCreatorCondition = quest.conditions.AvailableForFinish.find((x) => x._parent === "CounterCreator");
|
||||
const counterCreatorCondition = quest.conditions.AvailableForFinish.find((x) => x.conditionType === "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"
|
||||
const equipmentCondition = counterCreatorCondition.counter.conditions.find((x) =>
|
||||
x.conditionType === "Equipment"
|
||||
);
|
||||
(equipmentCondition._props as IEquipmentConditionProps).equipmentInclusive = [[
|
||||
equipmentCondition.equipmentInclusive = [[
|
||||
itemTypeToFetchWithCount.itemType,
|
||||
]];
|
||||
|
||||
@ -806,11 +799,13 @@ export class RepeatableQuestGenerator
|
||||
* @param {string} exit The exit name to generate the condition for
|
||||
* @returns {object} Exit condition
|
||||
*/
|
||||
protected generateExplorationExitCondition(exit: Exit): IExplorationCondition
|
||||
protected generateExplorationExitCondition(exit: Exit): IQuestConditionCounterCondition
|
||||
{
|
||||
return {
|
||||
_parent: "ExitName",
|
||||
_props: { exitName: exit.Name, id: this.objectId.generate(), dynamicLocale: true },
|
||||
conditionType: "ExitName",
|
||||
exitName: exit.Name,
|
||||
id: this.objectId.generate(),
|
||||
dynamicLocale: true,
|
||||
};
|
||||
}
|
||||
|
||||
@ -840,7 +835,7 @@ export class RepeatableQuestGenerator
|
||||
traderId: string,
|
||||
repeatableConfig: IRepeatableQuestConfig,
|
||||
questConfig: IBaseQuestConfig,
|
||||
): IRewards
|
||||
): IQuestRewards
|
||||
{
|
||||
// difficulty could go from 0.2 ... -> for lowest diffuculty receive 0.2*nominal reward
|
||||
const levelsConfig = repeatableConfig.rewardScaling.levels;
|
||||
@ -883,7 +878,7 @@ export class RepeatableQuestGenerator
|
||||
let roublesBudget = rewardRoubles;
|
||||
let rewardItemPool = this.chooseRewardItemsWithinBudget(repeatableConfig, roublesBudget, traderId);
|
||||
|
||||
const rewards: IRewards = {
|
||||
const rewards: IQuestRewards = {
|
||||
Started: [],
|
||||
Success: [],
|
||||
Fail: [],
|
||||
@ -893,7 +888,7 @@ export class RepeatableQuestGenerator
|
||||
// Add xp reward
|
||||
if (rewardXP > 0)
|
||||
{
|
||||
rewards.Success.push({ value: rewardXP, type: "Experience", index: rewardIndex });
|
||||
rewards.Success.push({ value: rewardXP, type: QuestRewardType.EXPERIENCE, index: rewardIndex });
|
||||
rewardIndex++;
|
||||
}
|
||||
|
||||
@ -987,7 +982,11 @@ export class RepeatableQuestGenerator
|
||||
// Add rep reward to rewards array
|
||||
if (rewardReputation > 0)
|
||||
{
|
||||
const reward: IReward = { target: traderId, value: rewardReputation, type: "TraderStanding", index: rewardIndex };
|
||||
const reward: IQuestReward = {
|
||||
target: traderId,
|
||||
value: rewardReputation,
|
||||
type: QuestRewardType.TRADER_STANDING,
|
||||
index: rewardIndex };
|
||||
rewards.Success.push(reward);
|
||||
rewardIndex++;
|
||||
}
|
||||
@ -995,10 +994,10 @@ export class RepeatableQuestGenerator
|
||||
// Chance of adding skill reward
|
||||
if (this.randomUtil.getChance100(skillRewardChance * 100))
|
||||
{
|
||||
const reward: IReward = {
|
||||
const reward: IQuestReward = {
|
||||
target: this.randomUtil.getArrayValue(questConfig.possibleSkillRewards),
|
||||
value: skillPointReward,
|
||||
type: "Skill",
|
||||
type: QuestRewardType.SKILL,
|
||||
index: rewardIndex,
|
||||
};
|
||||
rewards.Success.push(reward);
|
||||
@ -1028,10 +1027,13 @@ export class RepeatableQuestGenerator
|
||||
protected getRandomisedRewardItemStackSizeByPrice(item: ITemplateItem): number
|
||||
{
|
||||
const rewardItemPrice = this.itemHelper.getStaticItemPrice(item._id);
|
||||
if (rewardItemPrice < 3000) {
|
||||
if (rewardItemPrice < 3000)
|
||||
{
|
||||
return this.randomUtil.getArrayValue([2, 3, 4]);
|
||||
}
|
||||
else if (rewardItemPrice < 10000) {
|
||||
|
||||
if (rewardItemPrice < 10000)
|
||||
{
|
||||
return this.randomUtil.getArrayValue([2, 3]);
|
||||
}
|
||||
|
||||
@ -1082,10 +1084,10 @@ export class RepeatableQuestGenerator
|
||||
* @param {integer} index All rewards will be appended to a list, for unknown reasons the client wants the index
|
||||
* @returns {object} Object of "Reward"-item-type
|
||||
*/
|
||||
protected generateRewardItem(tpl: string, value: number, index: number, preset: Item[] = null): IReward
|
||||
protected generateRewardItem(tpl: string, value: number, index: number, preset: Item[] = null): IQuestReward
|
||||
{
|
||||
const id = this.objectId.generate();
|
||||
const rewardItem: IReward = { target: id, value: value, type: "Item", index: index };
|
||||
const rewardItem: IQuestReward = { target: id, value: value, type: QuestRewardType.ITEM, index: index };
|
||||
|
||||
if (preset)
|
||||
{
|
||||
|
@ -1,47 +1,47 @@
|
||||
import { injectable } from "tsyringe";
|
||||
|
||||
import { AvailableForConditions } from "@spt-aki/models/eft/common/tables/IQuest";
|
||||
import { IQuestCondition } from "@spt-aki/models/eft/common/tables/IQuest";
|
||||
|
||||
@injectable()
|
||||
export class QuestConditionHelper
|
||||
{
|
||||
public getQuestConditions(
|
||||
q: AvailableForConditions[],
|
||||
furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null,
|
||||
): AvailableForConditions[]
|
||||
q: IQuestCondition[],
|
||||
furtherFilter: (a: IQuestCondition) => IQuestCondition[] = null,
|
||||
): IQuestCondition[]
|
||||
{
|
||||
return this.filterConditions(q, "Quest", furtherFilter);
|
||||
}
|
||||
|
||||
public getLevelConditions(
|
||||
q: AvailableForConditions[],
|
||||
furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null,
|
||||
): AvailableForConditions[]
|
||||
q: IQuestCondition[],
|
||||
furtherFilter: (a: IQuestCondition) => IQuestCondition[] = null,
|
||||
): IQuestCondition[]
|
||||
{
|
||||
return this.filterConditions(q, "Level", furtherFilter);
|
||||
}
|
||||
|
||||
public getLoyaltyConditions(
|
||||
q: AvailableForConditions[],
|
||||
furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null,
|
||||
): AvailableForConditions[]
|
||||
q: IQuestCondition[],
|
||||
furtherFilter: (a: IQuestCondition) => IQuestCondition[] = null,
|
||||
): IQuestCondition[]
|
||||
{
|
||||
return this.filterConditions(q, "TraderLoyalty", furtherFilter);
|
||||
}
|
||||
|
||||
public getStandingConditions(
|
||||
q: AvailableForConditions[],
|
||||
furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null,
|
||||
): AvailableForConditions[]
|
||||
q: IQuestCondition[],
|
||||
furtherFilter: (a: IQuestCondition) => IQuestCondition[] = null,
|
||||
): IQuestCondition[]
|
||||
{
|
||||
return this.filterConditions(q, "TraderStanding", furtherFilter);
|
||||
}
|
||||
|
||||
protected filterConditions(
|
||||
q: AvailableForConditions[],
|
||||
q: IQuestCondition[],
|
||||
questType: string,
|
||||
furtherFilter: (a: AvailableForConditions) => AvailableForConditions[] = null,
|
||||
): AvailableForConditions[]
|
||||
furtherFilter: (a: IQuestCondition) => IQuestCondition[] = null,
|
||||
): IQuestCondition[]
|
||||
{
|
||||
const filteredQuests = q.filter((c) =>
|
||||
{
|
||||
|
@ -10,7 +10,7 @@ import { TraderHelper } from "@spt-aki/helpers/TraderHelper";
|
||||
import { IPmcData } from "@spt-aki/models/eft/common/IPmcData";
|
||||
import { Common, IQuestStatus } from "@spt-aki/models/eft/common/tables/IBotBase";
|
||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
import { AvailableForConditions, IQuest, Reward } from "@spt-aki/models/eft/common/tables/IQuest";
|
||||
import { IQuest, IQuestCondition, IQuestReward } from "@spt-aki/models/eft/common/tables/IQuest";
|
||||
import { IItemEventRouterResponse } from "@spt-aki/models/eft/itemEvent/IItemEventRouterResponse";
|
||||
import { IAcceptQuestRequestData } from "@spt-aki/models/eft/quests/IAcceptQuestRequestData";
|
||||
import { IFailQuestRequestData } from "@spt-aki/models/eft/quests/IFailQuestRequestData";
|
||||
@ -78,7 +78,7 @@ export class QuestHelper
|
||||
* @param condition Quest condition
|
||||
* @returns true if player level is greater than or equal to quest
|
||||
*/
|
||||
public doesPlayerLevelFulfilCondition(playerLevel: number, condition: AvailableForConditions): boolean
|
||||
public doesPlayerLevelFulfilCondition(playerLevel: number, condition: IQuestCondition): boolean
|
||||
{
|
||||
if (condition.conditionType === "Level")
|
||||
{
|
||||
@ -198,7 +198,7 @@ export class QuestHelper
|
||||
* @param profile Player profile
|
||||
* @returns true if loyalty is high enough to fulfill quest requirement
|
||||
*/
|
||||
public traderLoyaltyLevelRequirementCheck(questProperties: AvailableForConditions, profile: IPmcData): boolean
|
||||
public traderLoyaltyLevelRequirementCheck(questProperties: IQuestCondition, profile: IPmcData): boolean
|
||||
{
|
||||
const requiredLoyaltyLevel = Number(questProperties.value);
|
||||
const trader = profile.TradersInfo[<string>questProperties.target];
|
||||
@ -216,7 +216,7 @@ export class QuestHelper
|
||||
* @param profile Player profile
|
||||
* @returns true if standing is high enough to fulfill quest requirement
|
||||
*/
|
||||
public traderStandingRequirementCheck(questProperties: AvailableForConditions, profile: IPmcData): boolean
|
||||
public traderStandingRequirementCheck(questProperties: IQuestCondition, profile: IPmcData): boolean
|
||||
{
|
||||
const requiredStanding = Number(questProperties.value);
|
||||
const trader = profile.TradersInfo[<string>questProperties.target];
|
||||
@ -253,17 +253,17 @@ export class QuestHelper
|
||||
}
|
||||
|
||||
/**
|
||||
* take reward item from quest and set FiR status + fix stack sizes + fix mod Ids
|
||||
* @param reward Reward item to fix
|
||||
* Take reward item from quest and set FiR status + fix stack sizes + fix mod Ids
|
||||
* @param questReward Reward item to fix
|
||||
* @returns Fixed rewards
|
||||
*/
|
||||
protected processReward(reward: Reward): Reward[]
|
||||
protected processReward(questReward: IQuestReward): Item[]
|
||||
{
|
||||
let rewardItems: Reward[] = [];
|
||||
let rewardItems: Item[] = [];
|
||||
let targets: Item[] = [];
|
||||
const mods: Item[] = [];
|
||||
|
||||
for (const item of reward.items)
|
||||
for (const item of questReward.items)
|
||||
{
|
||||
// reward items are granted Found in Raid status
|
||||
if (!item.upd)
|
||||
@ -274,7 +274,7 @@ export class QuestHelper
|
||||
item.upd.SpawnedInSession = true;
|
||||
|
||||
// separate base item and mods, fix stacks
|
||||
if (item._id === reward.target)
|
||||
if (item._id === questReward.target)
|
||||
{
|
||||
if (
|
||||
(item.parentId !== undefined) && (item.parentId === "hideout")
|
||||
@ -311,7 +311,7 @@ export class QuestHelper
|
||||
items.push(this.jsonUtil.clone(mod));
|
||||
}
|
||||
|
||||
rewardItems = rewardItems.concat(<Reward[]>this.ragfairServerHelper.reparentPresets(target, items));
|
||||
rewardItems = rewardItems.concat(this.ragfairServerHelper.reparentPresets(target, items));
|
||||
}
|
||||
|
||||
return rewardItems;
|
||||
@ -323,11 +323,13 @@ export class QuestHelper
|
||||
* @param status Quest status that holds the items (Started, Success, Fail)
|
||||
* @returns array of items with the correct maxStack
|
||||
*/
|
||||
public getQuestRewardItems(quest: IQuest, status: QuestStatus): Reward[]
|
||||
public getQuestRewardItems(quest: IQuest, status: QuestStatus): Item[]
|
||||
{
|
||||
// Iterate over all rewards with the desired status, flatten out items that have a type of Item
|
||||
const questRewards = quest.rewards[QuestStatus[status]].flatMap((reward: Reward) =>
|
||||
reward.type === "Item" ? this.processReward(reward) : []
|
||||
const questRewards = quest.rewards[QuestStatus[status]].flatMap((reward: IQuestReward) =>
|
||||
reward.type === "Item"
|
||||
? this.processReward(reward)
|
||||
: []
|
||||
);
|
||||
|
||||
return questRewards;
|
||||
@ -410,7 +412,7 @@ export class QuestHelper
|
||||
const acceptedQuestCondition = quest.conditions.AvailableForStart.find((x) =>
|
||||
{
|
||||
return x.conditionType === "Quest"
|
||||
&& x.target === startedQuestId
|
||||
&& x.target.includes(startedQuestId)
|
||||
&& x.status[0] === QuestStatus.Started;
|
||||
});
|
||||
|
||||
@ -466,7 +468,7 @@ export class QuestHelper
|
||||
const acceptedQuestCondition = q.conditions.AvailableForStart.find((c) =>
|
||||
{
|
||||
return c.conditionType === "Quest"
|
||||
&& c.target === failedQuestId
|
||||
&& c.target.includes(failedQuestId)
|
||||
&& c.status[0] === QuestStatus.Fail;
|
||||
});
|
||||
|
||||
@ -495,7 +497,7 @@ export class QuestHelper
|
||||
*/
|
||||
public applyMoneyBoost(quest: IQuest, multiplier: number, questStatus: QuestStatus): IQuest
|
||||
{
|
||||
const rewards: Reward[] = quest.rewards?.[QuestStatus[questStatus]] ?? [];
|
||||
const rewards: IQuestReward[] = quest.rewards?.[QuestStatus[questStatus]] ?? [];
|
||||
for (const reward of rewards)
|
||||
{
|
||||
if (reward.type === "Item")
|
||||
@ -786,7 +788,7 @@ export class QuestHelper
|
||||
state: QuestStatus,
|
||||
sessionId: string,
|
||||
questResponse: IItemEventRouterResponse,
|
||||
): Reward[]
|
||||
): Item[]
|
||||
{
|
||||
// Repeatable quest base data is always in PMCProfile, `profileData` may be scav profile
|
||||
// TODO: consider moving repeatable quest data to profile-agnostic location
|
||||
@ -809,7 +811,7 @@ export class QuestHelper
|
||||
|
||||
// e.g. 'Success' or 'AvailableForFinish'
|
||||
const questStateAsString = QuestStatus[state];
|
||||
for (const reward of <Reward[]>questDetails.rewards[questStateAsString])
|
||||
for (const reward of <IQuestReward[]>questDetails.rewards[questStateAsString])
|
||||
{
|
||||
switch (reward.type)
|
||||
{
|
||||
@ -873,7 +875,7 @@ export class QuestHelper
|
||||
*/
|
||||
protected findAndAddHideoutProductionIdToProfile(
|
||||
pmcData: IPmcData,
|
||||
craftUnlockReward: Reward,
|
||||
craftUnlockReward: IQuestReward,
|
||||
questDetails: IQuest,
|
||||
sessionID: string,
|
||||
response: IItemEventRouterResponse,
|
||||
|
@ -1,12 +1,12 @@
|
||||
import { IQuestConditions, IRewards } from "./IQuest"
|
||||
import { IQuestConditionTypes, IQuestRewards } from "./IQuest"
|
||||
|
||||
export interface IAchievement
|
||||
{
|
||||
id: string
|
||||
imageUrl: string
|
||||
assetPath: string
|
||||
rewards: IRewards
|
||||
conditions: IQuestConditions
|
||||
rewards: IQuestRewards
|
||||
conditions: IQuestConditionTypes
|
||||
instantComplete: boolean
|
||||
showNotificationsInGame: boolean
|
||||
showProgress: boolean
|
||||
|
@ -9,7 +9,7 @@ export interface IQuest
|
||||
QuestName?: string;
|
||||
_id: string;
|
||||
canShowNotificationsInGame: boolean;
|
||||
conditions: IQuestConditions;
|
||||
conditions: IQuestConditionTypes;
|
||||
description: string;
|
||||
failMessageText: string;
|
||||
name: string;
|
||||
@ -26,8 +26,11 @@ export interface IQuest
|
||||
secretQuest: boolean;
|
||||
startedMessageText: string;
|
||||
successMessageText: string;
|
||||
acceptPlayerMessage: string;
|
||||
declinePlayerMessage: string;
|
||||
completePlayerMessage: string;
|
||||
templateId: string;
|
||||
rewards: IRewards;
|
||||
rewards: IQuestRewards;
|
||||
/** Becomes 'AppearStatus' inside client */
|
||||
status: string | number;
|
||||
KeyQuest: boolean;
|
||||
@ -38,26 +41,27 @@ export interface IQuest
|
||||
sptStatus?: QuestStatus;
|
||||
}
|
||||
|
||||
export interface IQuestConditions
|
||||
export interface IQuestConditionTypes
|
||||
{
|
||||
Started: AvailableForConditions[];
|
||||
AvailableForFinish: AvailableForConditions[];
|
||||
AvailableForStart: AvailableForConditions[];
|
||||
Success: AvailableForConditions[];
|
||||
Fail: AvailableForConditions[];
|
||||
Started: IQuestCondition[];
|
||||
AvailableForFinish: IQuestCondition[];
|
||||
AvailableForStart: IQuestCondition[];
|
||||
Success: IQuestCondition[];
|
||||
Fail: IQuestCondition[];
|
||||
}
|
||||
|
||||
export interface AvailableForConditions
|
||||
export interface IQuestCondition
|
||||
{
|
||||
id: string;
|
||||
index: number;
|
||||
parentId: string;
|
||||
isEncoded: boolean;
|
||||
index?: number;
|
||||
compareMethod?: string
|
||||
dynamicLocale: boolean;
|
||||
value?: string | number;
|
||||
compareMethod?: string;
|
||||
visibilityConditions?: VisibilityCondition[];
|
||||
target?: string | string[]; // TODO: split each availableForX object into each type: FindItem, HandoverItem, Level, Quest, TraderLoyalty etc
|
||||
globalQuestCounterId?: string
|
||||
parentId?: string;
|
||||
target: string[] | string;
|
||||
value?: string | number;
|
||||
type?: boolean;
|
||||
status?: QuestStatus[];
|
||||
availableAfter?: number;
|
||||
dispersion?: number;
|
||||
@ -67,42 +71,42 @@ export interface AvailableForConditions
|
||||
dogtagLevel?: number;
|
||||
maxDurability?: number;
|
||||
minDurability?: number;
|
||||
counter?: AvailableForCounter;
|
||||
counter?: IQuestConditionCounter;
|
||||
plantTime?: number;
|
||||
zoneId?: string;
|
||||
type?: boolean;
|
||||
countInRaid?: boolean;
|
||||
globalQuestCounterId?: string;
|
||||
completeInSeconds?: number
|
||||
conditionType?: string
|
||||
isEncoded?: boolean;
|
||||
conditionType?: string;
|
||||
}
|
||||
|
||||
export interface AvailableForCounter
|
||||
export interface IQuestConditionCounter
|
||||
{
|
||||
id: string;
|
||||
conditions: CounterCondition[];
|
||||
conditions: IQuestConditionCounterCondition[];
|
||||
}
|
||||
|
||||
export interface CounterCondition
|
||||
export interface IQuestConditionCounterCondition
|
||||
{
|
||||
id: string;
|
||||
completeInSeconds: number
|
||||
dynamicLocale: boolean
|
||||
target?: string[] | string; // TODO: some objects have an array and some are just strings, thanks bsg very cool
|
||||
completeInSeconds?: number
|
||||
energy?: IValueCompare
|
||||
exitName?: string;
|
||||
hydration?: IValueCompare
|
||||
time?: IValueCompare
|
||||
target: string[] | string; // TODO: some objects have an array and some are just strings, thanks bsg very cool
|
||||
compareMethod?: string;
|
||||
value?: string;
|
||||
value?: number;
|
||||
weapon?: string[];
|
||||
distance: ICounterConditionDistance
|
||||
distance?: ICounterConditionDistance
|
||||
equipmentInclusive?: string[][];
|
||||
weaponModsInclusive?: string[][];
|
||||
weaponModsExclusive?: string[][];
|
||||
enemyEquipmentInclusive?: string[][];
|
||||
enemyEquipmentExclusive?: string[][];
|
||||
weaponCaliber?: string[]
|
||||
savageRole: string[]
|
||||
savageRole?: string[]
|
||||
status?: string[];
|
||||
bodyPart?: string[];
|
||||
daytime?: IDaytimeCounter;
|
||||
@ -138,26 +142,28 @@ export interface IDaytimeCounter
|
||||
export interface VisibilityCondition
|
||||
{
|
||||
id: string;
|
||||
value: number;
|
||||
dynamicLocale: boolean;
|
||||
target: string
|
||||
value?: number;
|
||||
dynamicLocale?: boolean;
|
||||
oneSessionOnly: boolean;
|
||||
conditionType: string;
|
||||
}
|
||||
|
||||
export interface IRewards
|
||||
export interface IQuestRewards
|
||||
{
|
||||
AvailableForStart: Reward[];
|
||||
AvailableForFinish: Reward[];
|
||||
Started: Reward[];
|
||||
Success: Reward[];
|
||||
Fail: Reward[];
|
||||
FailRestartable: Reward[];
|
||||
Expired: Reward[];
|
||||
AvailableForStart?: IQuestReward[];
|
||||
AvailableForFinish?: IQuestReward[];
|
||||
Started?: IQuestReward[];
|
||||
Success?: IQuestReward[];
|
||||
Fail?: IQuestReward[];
|
||||
FailRestartable?: IQuestReward[];
|
||||
Expired?: IQuestReward[];
|
||||
}
|
||||
|
||||
export interface Reward extends Item
|
||||
export interface IQuestReward
|
||||
{
|
||||
value?: string | number;
|
||||
id: string;
|
||||
id?: string;
|
||||
type: QuestRewardType;
|
||||
index: number;
|
||||
target?: string;
|
||||
|
@ -1,27 +1,25 @@
|
||||
import { Item } from "@spt-aki/models/eft/common/tables/IItem";
|
||||
import { IQuest, IQuestConditionTypes, IQuestRewards } from "./IQuest";
|
||||
|
||||
export interface IReward
|
||||
export interface IRepeatableQuest extends IQuest
|
||||
{
|
||||
index: number;
|
||||
type: string;
|
||||
value: number;
|
||||
target?: string;
|
||||
items?: Item[];
|
||||
changeCost: IChangeCost[]
|
||||
changeStandingCost: number;
|
||||
sptRepatableGroupName: string
|
||||
}
|
||||
|
||||
export interface IRepeatableQuestDatabase
|
||||
{
|
||||
templates: ITemplates;
|
||||
templates: IRepeatableTemplates;
|
||||
rewards: IRewardOptions;
|
||||
data: IOptions;
|
||||
samples: ISampleQuests[];
|
||||
}
|
||||
|
||||
export interface ITemplates
|
||||
export interface IRepeatableTemplates
|
||||
{
|
||||
Elimination: IRepeatableQuest;
|
||||
Completion: IRepeatableQuest;
|
||||
Exploration: IRepeatableQuest;
|
||||
Elimination: IQuest;
|
||||
Completion: IQuest;
|
||||
Exploration: IQuest;
|
||||
}
|
||||
|
||||
export interface IPmcDataRepeatableQuest
|
||||
@ -31,11 +29,9 @@ export interface IPmcDataRepeatableQuest
|
||||
activeQuests: IRepeatableQuest[];
|
||||
inactiveQuests: IRepeatableQuest[];
|
||||
endTime: number;
|
||||
changeRequirement: TChangeRequirementRecord; // what it costs to reset <QuestId, ChangeRequirement> redundant to change requirements within the IRepeatableQuest
|
||||
changeRequirement: Record<string, IChangeRequirement>; // What it costs to reset <QuestId, ChangeRequirement> redundant to change requirements within IRepeatableQuest
|
||||
}
|
||||
|
||||
export type TChangeRequirementRecord = Record<string, IChangeRequirement>;
|
||||
|
||||
export interface IChangeRequirement
|
||||
{
|
||||
changeCost: IChangeCost[];
|
||||
@ -48,264 +44,6 @@ export interface IChangeCost
|
||||
count: number; // amount of item needed to reset
|
||||
}
|
||||
|
||||
export interface IRepeatableQuest
|
||||
{
|
||||
_id: string;
|
||||
traderId: string;
|
||||
location: string;
|
||||
image: string;
|
||||
type: string;
|
||||
isKey: boolean;
|
||||
restartable: boolean;
|
||||
instantComplete: boolean;
|
||||
secretQuest: boolean;
|
||||
canShowNotificationsInGame: boolean;
|
||||
rewards: IRewards;
|
||||
conditions: IConditions;
|
||||
side: string;
|
||||
questStatus: any;
|
||||
name: string;
|
||||
note: string;
|
||||
description: string;
|
||||
successMessageText: string;
|
||||
failMessageText: string;
|
||||
startedMessageText: string;
|
||||
changeQuestMessageText: string;
|
||||
acceptPlayerMessage: string;
|
||||
declinePlayerMessage: string;
|
||||
completePlayerMessage: string;
|
||||
templateId: string;
|
||||
changeCost: IChangeCost[];
|
||||
changeStandingCost: number;
|
||||
sptRepatableGroupName?: string;
|
||||
}
|
||||
|
||||
export interface IRewards
|
||||
{
|
||||
Started: IReward[];
|
||||
Success: IReward[];
|
||||
Fail: IReward[];
|
||||
}
|
||||
|
||||
export interface IConditions
|
||||
{
|
||||
AvailableForStart: any[];
|
||||
AvailableForFinish: IAvailableFor[];
|
||||
Fail: any[];
|
||||
}
|
||||
|
||||
export interface IAvailableFor
|
||||
{
|
||||
_props: IAvailableForProps;
|
||||
_parent: string;
|
||||
dynamicLocale: boolean;
|
||||
}
|
||||
|
||||
export interface IAvailableForProps
|
||||
{
|
||||
id: string;
|
||||
parentId: string;
|
||||
dynamicLocale: boolean;
|
||||
index: number;
|
||||
visibilityConditions: IVisibilityCondition[];
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface IVisibilityCondition
|
||||
{
|
||||
id: string;
|
||||
oneSessionOnly: boolean;
|
||||
value: number;
|
||||
index: number;
|
||||
dynamicLocale: boolean;
|
||||
}
|
||||
|
||||
export interface IAvailableForPropsCounter extends IAvailableForProps
|
||||
{
|
||||
type: string;
|
||||
oneSessionOnly: boolean;
|
||||
doNotResetIfCounterCompleted: boolean;
|
||||
counter?: ICounter;
|
||||
}
|
||||
|
||||
export interface ICounter
|
||||
{
|
||||
id: string;
|
||||
conditions: ICondition[];
|
||||
}
|
||||
|
||||
export interface ICondition
|
||||
{
|
||||
_props: IConditionProps;
|
||||
_parent: string;
|
||||
}
|
||||
|
||||
export interface IConditionProps
|
||||
{
|
||||
id: string;
|
||||
dynamicLocale: boolean;
|
||||
}
|
||||
|
||||
// Elimination
|
||||
export interface IElimination extends IRepeatableQuest
|
||||
{
|
||||
conditions: IEliminationConditions;
|
||||
}
|
||||
|
||||
export interface IEliminationConditions extends IConditions
|
||||
{
|
||||
AvailableForFinish: IEliminationAvailableFor[];
|
||||
}
|
||||
|
||||
export interface IEliminationAvailableFor extends IAvailableFor
|
||||
{
|
||||
_props: IEliminationAvailableForProps;
|
||||
}
|
||||
|
||||
export interface IEliminationAvailableForProps extends IAvailableForPropsCounter
|
||||
{
|
||||
counter: IEliminationCounter;
|
||||
}
|
||||
|
||||
export interface IEliminationCounter extends ICounter
|
||||
{
|
||||
conditions: IEliminationCondition[];
|
||||
}
|
||||
|
||||
export interface IEliminationCondition extends ICondition
|
||||
{
|
||||
_props: ILocationConditionProps | IKillConditionProps;
|
||||
}
|
||||
|
||||
// Exploration
|
||||
export interface IExploration extends IRepeatableQuest
|
||||
{
|
||||
conditions: IExplorationConditions;
|
||||
}
|
||||
|
||||
export interface IExplorationConditions extends IConditions
|
||||
{
|
||||
AvailableForFinish: IExplorationAvailableFor[];
|
||||
}
|
||||
|
||||
export interface IExplorationAvailableFor extends IAvailableFor
|
||||
{
|
||||
_props: IExplorationAvailableForProps;
|
||||
}
|
||||
|
||||
export interface IExplorationAvailableForProps extends IAvailableForPropsCounter
|
||||
{
|
||||
counter: IExplorationCounter;
|
||||
}
|
||||
|
||||
export interface IExplorationCounter extends ICounter
|
||||
{
|
||||
conditions: IExplorationCondition[];
|
||||
}
|
||||
|
||||
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
|
||||
{
|
||||
conditions: ICompletionConditions;
|
||||
}
|
||||
|
||||
export interface ICompletionConditions extends IConditions
|
||||
{
|
||||
AvailableForFinish: ICompletionAvailableFor[];
|
||||
}
|
||||
|
||||
export interface ICompletionAvailableFor extends IAvailableFor
|
||||
{
|
||||
_props: ICompletionAvailableForProps;
|
||||
}
|
||||
export interface ICompletionAvailableForProps extends IAvailableForProps
|
||||
{
|
||||
target: string[];
|
||||
minDurability: number;
|
||||
maxDurability: number;
|
||||
dogtagLevel: number;
|
||||
onlyFoundInRaid: boolean;
|
||||
}
|
||||
|
||||
// Quest Conditions
|
||||
|
||||
export interface ILocationConditionProps extends IConditionProps
|
||||
{
|
||||
target: string[];
|
||||
weapon?: string[];
|
||||
weaponCategories?: string[];
|
||||
}
|
||||
|
||||
export interface IEquipmentConditionProps extends IConditionProps
|
||||
{
|
||||
equipmentInclusive: [string[]];
|
||||
IncludeNotEquippedItems: boolean;
|
||||
}
|
||||
|
||||
export interface IKillConditionProps extends IConditionProps
|
||||
{
|
||||
target: string;
|
||||
value: number;
|
||||
savageRole?: string[];
|
||||
bodyPart?: string[];
|
||||
distance?: IDistanceCheck;
|
||||
weapon?: string[];
|
||||
weaponCategories?: string[];
|
||||
}
|
||||
|
||||
export interface IDistanceCheck
|
||||
{
|
||||
compareMethod: string;
|
||||
value: number;
|
||||
}
|
||||
|
||||
export interface IExitStatusConditionProps extends IConditionProps
|
||||
{
|
||||
status: string[];
|
||||
}
|
||||
|
||||
export interface IExitNameConditionProps extends IConditionProps
|
||||
{
|
||||
exitName: string;
|
||||
}
|
||||
|
||||
// Config Options
|
||||
|
||||
export interface IRewardOptions
|
||||
@ -348,8 +86,8 @@ export interface ISampleQuests
|
||||
instantComplete: boolean;
|
||||
secretQuest: boolean;
|
||||
canShowNotificationsInGame: boolean;
|
||||
rewards: IRewards;
|
||||
conditions: IConditions;
|
||||
rewards: IQuestRewards;
|
||||
conditions: IQuestConditionTypes;
|
||||
name: string;
|
||||
note: string;
|
||||
description: string;
|
||||
|
Loading…
Reference in New Issue
Block a user