mirror of
https://github.com/sp-tarkov/server.git
synced 2025-02-13 09:50:43 -05:00
Using live data, improved emulation accuracy of repeatable quest system
This commit is contained in:
parent
a15a28e460
commit
2abf216a07
@ -28,7 +28,10 @@
|
|||||||
"value": 1,
|
"value": 1,
|
||||||
"type": "Elimination",
|
"type": "Elimination",
|
||||||
"oneSessionOnly": false,
|
"oneSessionOnly": false,
|
||||||
|
"completeInSeconds": 0,
|
||||||
"doNotResetIfCounterCompleted": false,
|
"doNotResetIfCounterCompleted": false,
|
||||||
|
"isResetOnConditionFailed": false,
|
||||||
|
"isNecessary": false,
|
||||||
"counter": {
|
"counter": {
|
||||||
"id": "618c1de4d4cd91439f3de4ac",
|
"id": "618c1de4d4cd91439f3de4ac",
|
||||||
"conditions": [{
|
"conditions": [{
|
||||||
@ -74,13 +77,26 @@
|
|||||||
"acceptPlayerMessage": "{templateId} acceptPlayerMessage {traderId}",
|
"acceptPlayerMessage": "{templateId} acceptPlayerMessage {traderId}",
|
||||||
"declinePlayerMessage": "{templateId} declinePlayerMessage {traderId}",
|
"declinePlayerMessage": "{templateId} declinePlayerMessage {traderId}",
|
||||||
"completePlayerMessage": "{templateId} completePlayerMessage {traderId}",
|
"completePlayerMessage": "{templateId} completePlayerMessage {traderId}",
|
||||||
"templateId": "{templateId}",
|
"status": 0,
|
||||||
|
"acceptanceAndFinishingSource": "eft",
|
||||||
|
"progressSource": "eft",
|
||||||
|
"rankingModes": [],
|
||||||
|
"gameModes": [],
|
||||||
|
"arenaLocations": [],
|
||||||
"changeCost": [{
|
"changeCost": [{
|
||||||
"templateId": "5449016a4bdc2d6f028b456f",
|
"templateId": "5449016a4bdc2d6f028b456f",
|
||||||
"count": 5000
|
"count": 5000
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"changeStandingCost": 0
|
"changeStandingCost": 0,
|
||||||
|
"questStatus": {
|
||||||
|
"id": "mongoId",
|
||||||
|
"uid": "playerId",
|
||||||
|
"qid": "questId",
|
||||||
|
"startTime": 0,
|
||||||
|
"status": 1,
|
||||||
|
"statusTimers": {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Completion": {
|
"Completion": {
|
||||||
"_id": "61943a75eb60e11b7965cdbf4",
|
"_id": "61943a75eb60e11b7965cdbf4",
|
||||||
@ -114,13 +130,26 @@
|
|||||||
"acceptPlayerMessage": "{templateId} acceptPlayerMessage {traderId}",
|
"acceptPlayerMessage": "{templateId} acceptPlayerMessage {traderId}",
|
||||||
"declinePlayerMessage": "{templateId} declinePlayerMessage {traderId}",
|
"declinePlayerMessage": "{templateId} declinePlayerMessage {traderId}",
|
||||||
"completePlayerMessage": "{templateId} completePlayerMessage {traderId}",
|
"completePlayerMessage": "{templateId} completePlayerMessage {traderId}",
|
||||||
"templateId": "{templateId}",
|
"status": 0,
|
||||||
|
"acceptanceAndFinishingSource": "eft",
|
||||||
|
"progressSource": "eft",
|
||||||
|
"rankingModes": [],
|
||||||
|
"gameModes": [],
|
||||||
|
"arenaLocations": [],
|
||||||
"changeCost": [{
|
"changeCost": [{
|
||||||
"templateId": "5449016a4bdc2d6f028b456f",
|
"templateId": "5449016a4bdc2d6f028b456f",
|
||||||
"count": 5000
|
"count": 5000
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"changeStandingCost": 0
|
"changeStandingCost": 0,
|
||||||
|
"questStatus": {
|
||||||
|
"id": "mongoId",
|
||||||
|
"uid": "playerId",
|
||||||
|
"qid": "questId",
|
||||||
|
"startTime": 0,
|
||||||
|
"status": 1,
|
||||||
|
"statusTimers": {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Exploration": {
|
"Exploration": {
|
||||||
"_id": "65947c6afb90e7fcb40f8d684",
|
"_id": "65947c6afb90e7fcb40f8d684",
|
||||||
@ -185,13 +214,26 @@
|
|||||||
"acceptPlayerMessage": "{templateId} acceptPlayerMessage {traderId}",
|
"acceptPlayerMessage": "{templateId} acceptPlayerMessage {traderId}",
|
||||||
"declinePlayerMessage": "{templateId} declinePlayerMessage {traderId}",
|
"declinePlayerMessage": "{templateId} declinePlayerMessage {traderId}",
|
||||||
"completePlayerMessage": "{templateId} completePlayerMessage {traderId}",
|
"completePlayerMessage": "{templateId} completePlayerMessage {traderId}",
|
||||||
"templateId": "{templateId}",
|
"status": 0,
|
||||||
|
"acceptanceAndFinishingSource": "eft",
|
||||||
|
"progressSource": "eft",
|
||||||
|
"rankingModes": [],
|
||||||
|
"gameModes": [],
|
||||||
|
"arenaLocations": [],
|
||||||
"changeCost": [{
|
"changeCost": [{
|
||||||
"templateId": "5449016a4bdc2d6f028b456f",
|
"templateId": "5449016a4bdc2d6f028b456f",
|
||||||
"count": 5000
|
"count": 5000
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"changeStandingCost": 0
|
"changeStandingCost": 0,
|
||||||
|
"questStatus": {
|
||||||
|
"id": "mongoId",
|
||||||
|
"uid": "playerId",
|
||||||
|
"qid": "questId",
|
||||||
|
"startTime": 0,
|
||||||
|
"status": 1,
|
||||||
|
"statusTimers": {}
|
||||||
|
}
|
||||||
},
|
},
|
||||||
"Pickup": {
|
"Pickup": {
|
||||||
"_id": "64cfb3818db9f48b3f0b0a759",
|
"_id": "64cfb3818db9f48b3f0b0a759",
|
||||||
@ -217,7 +259,7 @@
|
|||||||
"dynamicLocale": false,
|
"dynamicLocale": false,
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"visibilityConditions": [],
|
"visibilityConditions": [],
|
||||||
"globalQuestCounterId": null,
|
"globalQuestCounterId": "",
|
||||||
"target": ["5b47574386f77428ca22b336"],
|
"target": ["5b47574386f77428ca22b336"],
|
||||||
"value": 7,
|
"value": 7,
|
||||||
"minDurability": 0,
|
"minDurability": 0,
|
||||||
@ -233,7 +275,7 @@
|
|||||||
"dynamicLocale": true,
|
"dynamicLocale": true,
|
||||||
"index": 0,
|
"index": 0,
|
||||||
"visibilityConditions": [],
|
"visibilityConditions": [],
|
||||||
"globalQuestCounterId": null,
|
"globalQuestCounterId": "",
|
||||||
"value": 1,
|
"value": 1,
|
||||||
"type": "PickUp",
|
"type": "PickUp",
|
||||||
"completeInSeconds": 0,
|
"completeInSeconds": 0,
|
||||||
@ -276,13 +318,26 @@
|
|||||||
"acceptPlayerMessage": "{templateId} acceptPlayerMessage {traderId}",
|
"acceptPlayerMessage": "{templateId} acceptPlayerMessage {traderId}",
|
||||||
"declinePlayerMessage": "{templateId} declinePlayerMessage {traderId}",
|
"declinePlayerMessage": "{templateId} declinePlayerMessage {traderId}",
|
||||||
"completePlayerMessage": "{templateId} completePlayerMessage {traderId}",
|
"completePlayerMessage": "{templateId} completePlayerMessage {traderId}",
|
||||||
"templateId": "{templateId}",
|
"status": 0,
|
||||||
|
"acceptanceAndFinishingSource": "eft",
|
||||||
|
"progressSource": "eft",
|
||||||
|
"rankingModes": [],
|
||||||
|
"gameModes": [],
|
||||||
|
"arenaLocations": [],
|
||||||
"changeCost": [{
|
"changeCost": [{
|
||||||
"templateId": "5449016a4bdc2d6f028b456f",
|
"templateId": "5449016a4bdc2d6f028b456f",
|
||||||
"count": 12000
|
"count": 12000
|
||||||
}
|
}
|
||||||
],
|
],
|
||||||
"changeStandingCost": 0
|
"changeStandingCost": 0,
|
||||||
|
"questStatus": {
|
||||||
|
"id": "mongoId",
|
||||||
|
"uid": "playerId",
|
||||||
|
"qid": "questId",
|
||||||
|
"startTime": 0,
|
||||||
|
"status": 1,
|
||||||
|
"statusTimers": {}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"rewards": {
|
"rewards": {
|
||||||
|
@ -174,6 +174,7 @@ export class QuestController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
* TODO - Move this code into RepeatableQuestController
|
||||||
* Handle the client accepting a repeatable quest and starting it
|
* Handle the client accepting a repeatable quest and starting it
|
||||||
* Send starting rewards if any to player and
|
* Send starting rewards if any to player and
|
||||||
* Send start notification if any to player
|
* Send start notification if any to player
|
||||||
@ -221,50 +222,11 @@ export class QuestController {
|
|||||||
fullProfile.characters.scav.Quests.push(newRepeatableQuest);
|
fullProfile.characters.scav.Quests.push(newRepeatableQuest);
|
||||||
}
|
}
|
||||||
|
|
||||||
const response = this.createAcceptedQuestClientResponse(sessionID, pmcData, repeatableQuestProfile);
|
const response = this.eventOutputHolder.getOutput(sessionID);
|
||||||
|
|
||||||
return response;
|
return response;
|
||||||
}
|
}
|
||||||
|
|
||||||
protected createAcceptedQuestClientResponse(
|
|
||||||
sessionID: string,
|
|
||||||
pmcData: IPmcData,
|
|
||||||
repeatableQuestProfile: IRepeatableQuest,
|
|
||||||
): IItemEventRouterResponse {
|
|
||||||
const repeatableSettings = pmcData.RepeatableQuests.find(
|
|
||||||
(quest) => quest.name === repeatableQuestProfile.sptRepatableGroupName,
|
|
||||||
);
|
|
||||||
|
|
||||||
const change = {};
|
|
||||||
change[repeatableQuestProfile._id] = repeatableSettings.changeRequirement[repeatableQuestProfile._id];
|
|
||||||
|
|
||||||
const repeatableData: IPmcDataRepeatableQuest = {
|
|
||||||
id:
|
|
||||||
repeatableSettings.id ??
|
|
||||||
this.questConfig.repeatableQuests.find(
|
|
||||||
(repeatableQuest) => repeatableQuest.name === repeatableQuestProfile.sptRepatableGroupName,
|
|
||||||
).id,
|
|
||||||
name: repeatableSettings.name,
|
|
||||||
endTime: repeatableSettings.endTime,
|
|
||||||
changeRequirement: change,
|
|
||||||
activeQuests: [repeatableQuestProfile],
|
|
||||||
inactiveQuests: [],
|
|
||||||
freeChanges: repeatableSettings.freeChanges,
|
|
||||||
freeChangesAvailable: repeatableSettings.freeChangesAvailable,
|
|
||||||
};
|
|
||||||
|
|
||||||
// Nullguard
|
|
||||||
const acceptQuestResponse = this.eventOutputHolder.getOutput(sessionID);
|
|
||||||
if (!acceptQuestResponse.profileChanges[sessionID].repeatableQuests) {
|
|
||||||
acceptQuestResponse.profileChanges[sessionID].repeatableQuests = [];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Add constructed objet into response
|
|
||||||
acceptQuestResponse.profileChanges[sessionID].repeatableQuests.push(repeatableData);
|
|
||||||
|
|
||||||
return acceptQuestResponse;
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Look for an accepted quest inside player profile, return matching
|
* Look for an accepted quest inside player profile, return matching
|
||||||
* @param pmcData Profile to search through
|
* @param pmcData Profile to search through
|
||||||
|
@ -129,6 +129,7 @@ export class RepeatableQuestController {
|
|||||||
let lifeline = 0;
|
let lifeline = 0;
|
||||||
while (!quest && questTypePool.types.length > 0) {
|
while (!quest && questTypePool.types.length > 0) {
|
||||||
quest = this.repeatableQuestGenerator.generateRepeatableQuest(
|
quest = this.repeatableQuestGenerator.generateRepeatableQuest(
|
||||||
|
sessionID,
|
||||||
pmcData.Info.Level,
|
pmcData.Info.Level,
|
||||||
pmcData.TradersInfo,
|
pmcData.TradersInfo,
|
||||||
questTypePool,
|
questTypePool,
|
||||||
@ -487,11 +488,11 @@ export class RepeatableQuestController {
|
|||||||
const fullProfile = this.profileHelper.getFullProfile(sessionID);
|
const fullProfile = this.profileHelper.getFullProfile(sessionID);
|
||||||
|
|
||||||
// Check for existing quest in (daily/weekly/scav arrays)
|
// Check for existing quest in (daily/weekly/scav arrays)
|
||||||
const { quest: questToReplace, repeatableType: repeatablesInProfile } = this.getRepeatableById(
|
const { quest: questToReplace, repeatableType: repeatablesOfTypeInProfile } = this.getRepeatableById(
|
||||||
changeRequest.qid,
|
changeRequest.qid,
|
||||||
pmcData,
|
pmcData,
|
||||||
);
|
);
|
||||||
if (!repeatablesInProfile || !questToReplace) {
|
if (!repeatablesOfTypeInProfile || !questToReplace) {
|
||||||
// Unable to find quest being replaced
|
// Unable to find quest being replaced
|
||||||
const message = this.localisationService.getText("quest-unable_to_find_repeatable_to_replace");
|
const message = this.localisationService.getText("quest-unable_to_find_repeatable_to_replace");
|
||||||
this.logger.error(message);
|
this.logger.error(message);
|
||||||
@ -500,25 +501,27 @@ export class RepeatableQuestController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Subtype name of quest - daily/weekly/scav
|
// Subtype name of quest - daily/weekly/scav
|
||||||
const repeatableTypeLower = repeatablesInProfile.name.toLowerCase();
|
const repeatableTypeLower = repeatablesOfTypeInProfile.name.toLowerCase();
|
||||||
|
|
||||||
// Save for later standing loss calculation
|
// Save for later standing loss calculation
|
||||||
const replacedQuestTraderId = questToReplace.traderId;
|
const replacedQuestTraderId = questToReplace.traderId;
|
||||||
|
|
||||||
// Update active quests to exclude the quest we're replacing
|
// Update active quests to exclude the quest we're replacing
|
||||||
repeatablesInProfile.activeQuests = repeatablesInProfile.activeQuests.filter(
|
repeatablesOfTypeInProfile.activeQuests = repeatablesOfTypeInProfile.activeQuests.filter(
|
||||||
(quest) => quest._id !== changeRequest.qid,
|
(quest) => quest._id !== changeRequest.qid,
|
||||||
);
|
);
|
||||||
|
|
||||||
// Save for later cost calculation
|
// Save for later cost calculations
|
||||||
const previousChangeRequirement = this.cloner.clone(repeatablesInProfile.changeRequirement[changeRequest.qid]);
|
const previousChangeRequirement = this.cloner.clone(
|
||||||
|
repeatablesOfTypeInProfile.changeRequirement[changeRequest.qid],
|
||||||
|
);
|
||||||
|
|
||||||
// Delete the replaced quest change requrement as we're going to replace it
|
// Delete the replaced quest change requirement data as we're going to add new data below
|
||||||
delete repeatablesInProfile.changeRequirement[changeRequest.qid];
|
delete repeatablesOfTypeInProfile.changeRequirement[changeRequest.qid];
|
||||||
|
|
||||||
// Get config for this repeatable sub-type (daily/weekly/scav)
|
// Get config for this repeatable sub-type (daily/weekly/scav)
|
||||||
const repeatableConfig = this.questConfig.repeatableQuests.find(
|
const repeatableConfig = this.questConfig.repeatableQuests.find(
|
||||||
(config) => config.name === repeatablesInProfile.name,
|
(config) => config.name === repeatablesOfTypeInProfile.name,
|
||||||
);
|
);
|
||||||
|
|
||||||
// If the configuration dictates to replace with the same quest type, adjust the available quest types
|
// If the configuration dictates to replace with the same quest type, adjust the available quest types
|
||||||
@ -535,7 +538,12 @@ export class RepeatableQuestController {
|
|||||||
|
|
||||||
// Generate meta-data for what type/levelrange of quests can be generated for player
|
// Generate meta-data for what type/levelrange of quests can be generated for player
|
||||||
const allowedQuestTypes = this.generateQuestPool(repeatableConfig, pmcData.Info.Level);
|
const allowedQuestTypes = this.generateQuestPool(repeatableConfig, pmcData.Info.Level);
|
||||||
const newRepeatableQuest = this.attemptToGenerateRepeatableQuest(pmcData, allowedQuestTypes, repeatableConfig);
|
const newRepeatableQuest = this.attemptToGenerateRepeatableQuest(
|
||||||
|
sessionID,
|
||||||
|
pmcData,
|
||||||
|
allowedQuestTypes,
|
||||||
|
repeatableConfig,
|
||||||
|
);
|
||||||
if (!newRepeatableQuest) {
|
if (!newRepeatableQuest) {
|
||||||
// Unable to find quest being replaced
|
// Unable to find quest being replaced
|
||||||
const message = `Unable to generate repeatable quest of type: ${repeatableTypeLower} to replace trader: ${replacedQuestTraderId} quest ${changeRequest.qid}`;
|
const message = `Unable to generate repeatable quest of type: ${repeatableTypeLower} to replace trader: ${replacedQuestTraderId} quest ${changeRequest.qid}`;
|
||||||
@ -546,7 +554,7 @@ export class RepeatableQuestController {
|
|||||||
|
|
||||||
// Add newly generated quest to daily/weekly/scav type array
|
// Add newly generated quest to daily/weekly/scav type array
|
||||||
newRepeatableQuest.side = repeatableConfig.side;
|
newRepeatableQuest.side = repeatableConfig.side;
|
||||||
repeatablesInProfile.activeQuests.push(newRepeatableQuest);
|
repeatablesOfTypeInProfile.activeQuests.push(newRepeatableQuest);
|
||||||
|
|
||||||
this.logger.debug(
|
this.logger.debug(
|
||||||
`Removing: ${repeatableConfig.name} quest: ${questToReplace._id} from trader: ${questToReplace.traderId} as its been replaced`,
|
`Removing: ${repeatableConfig.name} quest: ${questToReplace._id} from trader: ${questToReplace.traderId} as its been replaced`,
|
||||||
@ -562,13 +570,17 @@ export class RepeatableQuestController {
|
|||||||
);
|
);
|
||||||
|
|
||||||
// Add new quests replacement cost to profile
|
// Add new quests replacement cost to profile
|
||||||
repeatablesInProfile.changeRequirement[newRepeatableQuest._id] = {
|
repeatablesOfTypeInProfile.changeRequirement[newRepeatableQuest._id] = {
|
||||||
changeCost: newRepeatableQuest.changeCost,
|
changeCost: newRepeatableQuest.changeCost,
|
||||||
changeStandingCost: this.randomUtil.getArrayValue([0, 0.01]),
|
changeStandingCost: this.randomUtil.getArrayValue([0, 0.01]),
|
||||||
};
|
};
|
||||||
|
|
||||||
// Check if we should charge player for replacing quest
|
// Check if we should charge player for replacing quest
|
||||||
const isFreeToReplace = this.useFreeRefreshIfAvailable(fullProfile, repeatablesInProfile, repeatableTypeLower);
|
const isFreeToReplace = this.useFreeRefreshIfAvailable(
|
||||||
|
fullProfile,
|
||||||
|
repeatablesOfTypeInProfile,
|
||||||
|
repeatableTypeLower,
|
||||||
|
);
|
||||||
if (!isFreeToReplace) {
|
if (!isFreeToReplace) {
|
||||||
// Reduce standing with trader for not doing their quest
|
// Reduce standing with trader for not doing their quest
|
||||||
const traderOfReplacedQuest = pmcData.TradersInfo[replacedQuestTraderId];
|
const traderOfReplacedQuest = pmcData.TradersInfo[replacedQuestTraderId];
|
||||||
@ -586,7 +598,7 @@ export class RepeatableQuestController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Clone data before we send it to client
|
// Clone data before we send it to client
|
||||||
const repeatableToChangeClone = this.cloner.clone(repeatablesInProfile);
|
const repeatableToChangeClone = this.cloner.clone(repeatablesOfTypeInProfile);
|
||||||
|
|
||||||
// Purge inactive repeatables
|
// Purge inactive repeatables
|
||||||
repeatableToChangeClone.inactiveQuests = [];
|
repeatableToChangeClone.inactiveQuests = [];
|
||||||
@ -622,6 +634,7 @@ export class RepeatableQuestController {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected attemptToGenerateRepeatableQuest(
|
protected attemptToGenerateRepeatableQuest(
|
||||||
|
sessionId: string,
|
||||||
pmcData: IPmcData,
|
pmcData: IPmcData,
|
||||||
questTypePool: IQuestTypePool,
|
questTypePool: IQuestTypePool,
|
||||||
repeatableConfig: IRepeatableQuestConfig,
|
repeatableConfig: IRepeatableQuestConfig,
|
||||||
@ -631,6 +644,7 @@ export class RepeatableQuestController {
|
|||||||
let attempts = 0;
|
let attempts = 0;
|
||||||
while (attempts < maxAttempts && questTypePool.types.length > 0) {
|
while (attempts < maxAttempts && questTypePool.types.length > 0) {
|
||||||
newRepeatableQuest = this.repeatableQuestGenerator.generateRepeatableQuest(
|
newRepeatableQuest = this.repeatableQuestGenerator.generateRepeatableQuest(
|
||||||
|
sessionId,
|
||||||
pmcData.Info.Level,
|
pmcData.Info.Level,
|
||||||
pmcData.TradersInfo,
|
pmcData.TradersInfo,
|
||||||
questTypePool,
|
questTypePool,
|
||||||
|
@ -50,6 +50,7 @@ export class RepeatableQuestGenerator {
|
|||||||
/**
|
/**
|
||||||
* This method is called by /GetClientRepeatableQuests/ and creates one element of quest type format (see assets/database/templates/repeatableQuests.json).
|
* This method is called by /GetClientRepeatableQuests/ and creates one element of quest type format (see assets/database/templates/repeatableQuests.json).
|
||||||
* It randomly draws a quest type (currently Elimination, Completion or Exploration) as well as a trader who is providing the quest
|
* It randomly draws a quest type (currently Elimination, Completion or Exploration) as well as a trader who is providing the quest
|
||||||
|
* @param sessionId Session id
|
||||||
* @param pmcLevel Player's level for requested items and reward generation
|
* @param pmcLevel Player's level for requested items and reward generation
|
||||||
* @param pmcTraderInfo Players traper standing/rep levels
|
* @param pmcTraderInfo Players traper standing/rep levels
|
||||||
* @param questTypePool Possible quest types pool
|
* @param questTypePool Possible quest types pool
|
||||||
@ -57,6 +58,7 @@ export class RepeatableQuestGenerator {
|
|||||||
* @returns IRepeatableQuest
|
* @returns IRepeatableQuest
|
||||||
*/
|
*/
|
||||||
public generateRepeatableQuest(
|
public generateRepeatableQuest(
|
||||||
|
sessionId: string,
|
||||||
pmcLevel: number,
|
pmcLevel: number,
|
||||||
pmcTraderInfo: Record<string, ITraderInfo>,
|
pmcTraderInfo: Record<string, ITraderInfo>,
|
||||||
questTypePool: IQuestTypePool,
|
questTypePool: IQuestTypePool,
|
||||||
@ -64,7 +66,7 @@ export class RepeatableQuestGenerator {
|
|||||||
): IRepeatableQuest {
|
): IRepeatableQuest {
|
||||||
const questType = this.randomUtil.drawRandomFromList<string>(questTypePool.types)[0];
|
const questType = this.randomUtil.drawRandomFromList<string>(questTypePool.types)[0];
|
||||||
|
|
||||||
// get traders from whitelist and filter by quest type availability
|
// Get traders from whitelist and filter by quest type availability
|
||||||
let traders = repeatableConfig.traderWhitelist
|
let traders = repeatableConfig.traderWhitelist
|
||||||
.filter((x) => x.questTypes.includes(questType))
|
.filter((x) => x.questTypes.includes(questType))
|
||||||
.map((x) => x.traderId);
|
.map((x) => x.traderId);
|
||||||
@ -74,13 +76,13 @@ export class RepeatableQuestGenerator {
|
|||||||
|
|
||||||
switch (questType) {
|
switch (questType) {
|
||||||
case "Elimination":
|
case "Elimination":
|
||||||
return this.generateEliminationQuest(pmcLevel, traderId, questTypePool, repeatableConfig);
|
return this.generateEliminationQuest(sessionId, pmcLevel, traderId, questTypePool, repeatableConfig);
|
||||||
case "Completion":
|
case "Completion":
|
||||||
return this.generateCompletionQuest(pmcLevel, traderId, repeatableConfig);
|
return this.generateCompletionQuest(sessionId, pmcLevel, traderId, repeatableConfig);
|
||||||
case "Exploration":
|
case "Exploration":
|
||||||
return this.generateExplorationQuest(pmcLevel, traderId, questTypePool, repeatableConfig);
|
return this.generateExplorationQuest(sessionId, pmcLevel, traderId, questTypePool, repeatableConfig);
|
||||||
case "Pickup":
|
case "Pickup":
|
||||||
return this.generatePickupQuest(pmcLevel, traderId, questTypePool, repeatableConfig);
|
return this.generatePickupQuest(sessionId, pmcLevel, traderId, questTypePool, repeatableConfig);
|
||||||
default:
|
default:
|
||||||
throw new Error(`Unknown mission type ${questType}. Should never be here!`);
|
throw new Error(`Unknown mission type ${questType}. Should never be here!`);
|
||||||
}
|
}
|
||||||
@ -95,6 +97,7 @@ export class RepeatableQuestGenerator {
|
|||||||
* @returns Object of quest type format for "Elimination" (see assets/database/templates/repeatableQuests.json)
|
* @returns Object of quest type format for "Elimination" (see assets/database/templates/repeatableQuests.json)
|
||||||
*/
|
*/
|
||||||
protected generateEliminationQuest(
|
protected generateEliminationQuest(
|
||||||
|
sessionid: string,
|
||||||
pmcLevel: number,
|
pmcLevel: number,
|
||||||
traderId: string,
|
traderId: string,
|
||||||
questTypePool: IQuestTypePool,
|
questTypePool: IQuestTypePool,
|
||||||
@ -297,7 +300,7 @@ export class RepeatableQuestGenerator {
|
|||||||
// crazy maximum difficulty will lead to a higher difficulty reward gain factor than 1
|
// 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 difficulty = this.mathUtil.mapToRange(curDifficulty, minDifficulty, maxDifficulty, 0.5, 2);
|
||||||
|
|
||||||
const quest = this.generateRepeatableTemplate("Elimination", traderId, repeatableConfig.side);
|
const quest = this.generateRepeatableTemplate("Elimination", traderId, repeatableConfig.side, sessionid);
|
||||||
|
|
||||||
// ASSUMPTION: All fence quests are for scavs
|
// ASSUMPTION: All fence quests are for scavs
|
||||||
if (traderId === Traders.FENCE) {
|
if (traderId === Traders.FENCE) {
|
||||||
@ -396,10 +399,13 @@ export class RepeatableQuestGenerator {
|
|||||||
allowedWeaponCategory: string,
|
allowedWeaponCategory: string,
|
||||||
): IQuestConditionCounterCondition {
|
): IQuestConditionCounterCondition {
|
||||||
const killConditionProps: IQuestConditionCounterCondition = {
|
const killConditionProps: IQuestConditionCounterCondition = {
|
||||||
target: target,
|
|
||||||
value: 1,
|
|
||||||
id: this.objectId.generate(),
|
id: this.objectId.generate(),
|
||||||
dynamicLocale: true,
|
dynamicLocale: true,
|
||||||
|
target: target, // e,g, "AnyPmc"
|
||||||
|
value: 1,
|
||||||
|
resetOnSessionEnd: false,
|
||||||
|
enemyHealthEffects: [],
|
||||||
|
daytime: { from: 0, to: 0 },
|
||||||
conditionType: "Kills",
|
conditionType: "Kills",
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -441,6 +447,7 @@ export class RepeatableQuestGenerator {
|
|||||||
* @returns {object} object of quest type format for "Completion" (see assets/database/templates/repeatableQuests.json)
|
* @returns {object} object of quest type format for "Completion" (see assets/database/templates/repeatableQuests.json)
|
||||||
*/
|
*/
|
||||||
protected generateCompletionQuest(
|
protected generateCompletionQuest(
|
||||||
|
sessionId: string,
|
||||||
pmcLevel: number,
|
pmcLevel: number,
|
||||||
traderId: string,
|
traderId: string,
|
||||||
repeatableConfig: IRepeatableQuestConfig,
|
repeatableConfig: IRepeatableQuestConfig,
|
||||||
@ -449,7 +456,7 @@ export class RepeatableQuestGenerator {
|
|||||||
const levelsConfig = repeatableConfig.rewardScaling.levels;
|
const levelsConfig = repeatableConfig.rewardScaling.levels;
|
||||||
const roublesConfig = repeatableConfig.rewardScaling.roubles;
|
const roublesConfig = repeatableConfig.rewardScaling.roubles;
|
||||||
|
|
||||||
const quest = this.generateRepeatableTemplate("Completion", traderId, repeatableConfig.side);
|
const quest = this.generateRepeatableTemplate("Completion", traderId, repeatableConfig.side, sessionId);
|
||||||
|
|
||||||
// Filter the items.json items to items the player must retrieve to complete quest: shouldn't be a quest item or "non-existant"
|
// 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.repeatableQuestRewardGenerator.getRewardableItems(
|
const possibleItemsToRetrievePool = this.repeatableQuestRewardGenerator.getRewardableItems(
|
||||||
@ -626,16 +633,18 @@ export class RepeatableQuestGenerator {
|
|||||||
|
|
||||||
return {
|
return {
|
||||||
id: this.objectId.generate(),
|
id: this.objectId.generate(),
|
||||||
|
index: 0,
|
||||||
parentId: "",
|
parentId: "",
|
||||||
dynamicLocale: true,
|
dynamicLocale: true,
|
||||||
index: 0,
|
|
||||||
visibilityConditions: [],
|
visibilityConditions: [],
|
||||||
|
globalQuestCounterId: "",
|
||||||
target: [itemTpl],
|
target: [itemTpl],
|
||||||
value: value,
|
value: value,
|
||||||
minDurability: minDurability,
|
minDurability: minDurability,
|
||||||
maxDurability: 100,
|
maxDurability: 100,
|
||||||
dogtagLevel: 0,
|
dogtagLevel: 0,
|
||||||
onlyFoundInRaid: onlyFoundInRaid,
|
onlyFoundInRaid: onlyFoundInRaid,
|
||||||
|
isEncoded: false,
|
||||||
conditionType: "HandoverItem",
|
conditionType: "HandoverItem",
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@ -650,6 +659,7 @@ export class RepeatableQuestGenerator {
|
|||||||
* @returns {object} object of quest type format for "Exploration" (see assets/database/templates/repeatableQuests.json)
|
* @returns {object} object of quest type format for "Exploration" (see assets/database/templates/repeatableQuests.json)
|
||||||
*/
|
*/
|
||||||
protected generateExplorationQuest(
|
protected generateExplorationQuest(
|
||||||
|
sessionId: string,
|
||||||
pmcLevel: number,
|
pmcLevel: number,
|
||||||
traderId: string,
|
traderId: string,
|
||||||
questTypePool: IQuestTypePool,
|
questTypePool: IQuestTypePool,
|
||||||
@ -679,19 +689,19 @@ export class RepeatableQuestGenerator {
|
|||||||
: explorationConfig.maxExtracts + 1;
|
: explorationConfig.maxExtracts + 1;
|
||||||
const numExtracts = this.randomUtil.randInt(1, exitTimesMax);
|
const numExtracts = this.randomUtil.randInt(1, exitTimesMax);
|
||||||
|
|
||||||
const quest = this.generateRepeatableTemplate("Exploration", traderId, repeatableConfig.side);
|
const quest = this.generateRepeatableTemplate("Exploration", traderId, repeatableConfig.side, sessionId);
|
||||||
|
|
||||||
const exitStatusCondition: IQuestConditionCounterCondition = {
|
const exitStatusCondition: IQuestConditionCounterCondition = {
|
||||||
conditionType: "ExitStatus",
|
|
||||||
id: this.objectId.generate(),
|
id: this.objectId.generate(),
|
||||||
dynamicLocale: true,
|
dynamicLocale: true,
|
||||||
status: ["Survived"],
|
status: ["Survived"],
|
||||||
|
conditionType: "ExitStatus",
|
||||||
};
|
};
|
||||||
const locationCondition: IQuestConditionCounterCondition = {
|
const locationCondition: IQuestConditionCounterCondition = {
|
||||||
conditionType: "Location",
|
|
||||||
id: this.objectId.generate(),
|
id: this.objectId.generate(),
|
||||||
dynamicLocale: true,
|
dynamicLocale: true,
|
||||||
target: locationTarget,
|
target: locationTarget,
|
||||||
|
conditionType: "Location",
|
||||||
};
|
};
|
||||||
|
|
||||||
quest.conditions.AvailableForFinish[0].counter.id = this.objectId.generate();
|
quest.conditions.AvailableForFinish[0].counter.id = this.objectId.generate();
|
||||||
@ -757,6 +767,7 @@ export class RepeatableQuestGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
protected generatePickupQuest(
|
protected generatePickupQuest(
|
||||||
|
sessionId: string,
|
||||||
pmcLevel: number,
|
pmcLevel: number,
|
||||||
traderId: string,
|
traderId: string,
|
||||||
questTypePool: IQuestTypePool,
|
questTypePool: IQuestTypePool,
|
||||||
@ -764,7 +775,7 @@ export class RepeatableQuestGenerator {
|
|||||||
): IRepeatableQuest {
|
): IRepeatableQuest {
|
||||||
const pickupConfig = repeatableConfig.questConfig.Pickup;
|
const pickupConfig = repeatableConfig.questConfig.Pickup;
|
||||||
|
|
||||||
const quest = this.generateRepeatableTemplate("Pickup", traderId, repeatableConfig.side);
|
const quest = this.generateRepeatableTemplate("Pickup", traderId, repeatableConfig.side, sessionId);
|
||||||
|
|
||||||
const itemTypeToFetchWithCount = this.randomUtil.getArrayValue(pickupConfig.ItemTypeToFetchWithMaxCount);
|
const itemTypeToFetchWithCount = this.randomUtil.getArrayValue(pickupConfig.ItemTypeToFetchWithMaxCount);
|
||||||
const itemCountToFetch = this.randomUtil.randInt(
|
const itemCountToFetch = this.randomUtil.randInt(
|
||||||
@ -819,7 +830,12 @@ export class RepeatableQuestGenerator {
|
|||||||
* @returns {object} Exit condition
|
* @returns {object} Exit condition
|
||||||
*/
|
*/
|
||||||
protected generateExplorationExitCondition(exit: IExit): IQuestConditionCounterCondition {
|
protected generateExplorationExitCondition(exit: IExit): IQuestConditionCounterCondition {
|
||||||
return { conditionType: "ExitName", exitName: exit.Name, id: this.objectId.generate(), dynamicLocale: true };
|
return {
|
||||||
|
id: this.objectId.generate(),
|
||||||
|
dynamicLocale: true,
|
||||||
|
exitName: exit.Name,
|
||||||
|
conditionType: "ExitName",
|
||||||
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -833,7 +849,12 @@ export class RepeatableQuestGenerator {
|
|||||||
* (needs to be filled with reward and conditions by called to make a valid quest)
|
* (needs to be filled with reward and conditions by called to make a valid quest)
|
||||||
*/
|
*/
|
||||||
// @Incomplete: define Type for "type".
|
// @Incomplete: define Type for "type".
|
||||||
protected generateRepeatableTemplate(type: string, traderId: string, side: string): IRepeatableQuest {
|
protected generateRepeatableTemplate(
|
||||||
|
type: string,
|
||||||
|
traderId: string,
|
||||||
|
side: string,
|
||||||
|
sessionId: string,
|
||||||
|
): IRepeatableQuest {
|
||||||
const questClone = this.cloner.clone<IRepeatableQuest>(
|
const questClone = this.cloner.clone<IRepeatableQuest>(
|
||||||
this.databaseService.getTemplates().repeatableQuests.templates[type],
|
this.databaseService.getTemplates().repeatableQuests.templates[type],
|
||||||
);
|
);
|
||||||
@ -882,6 +903,10 @@ export class RepeatableQuestGenerator {
|
|||||||
.replace("{traderId}", desiredTraderId)
|
.replace("{traderId}", desiredTraderId)
|
||||||
.replace("{templateId}", questClone.templateId);
|
.replace("{templateId}", questClone.templateId);
|
||||||
|
|
||||||
|
questClone.questStatus.id = this.objectId.generate();
|
||||||
|
questClone.questStatus.uid = sessionId; // Needs to match user id
|
||||||
|
questClone.questStatus.qid = questClone._id; // Needs to match quest id
|
||||||
|
|
||||||
return questClone;
|
return questClone;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -23,6 +23,7 @@ import { DatabaseService } from "@spt/services/DatabaseService";
|
|||||||
import { ItemFilterService } from "@spt/services/ItemFilterService";
|
import { ItemFilterService } from "@spt/services/ItemFilterService";
|
||||||
import { LocalisationService } from "@spt/services/LocalisationService";
|
import { LocalisationService } from "@spt/services/LocalisationService";
|
||||||
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
|
import { SeasonalEventService } from "@spt/services/SeasonalEventService";
|
||||||
|
import { HashUtil } from "@spt/utils/HashUtil";
|
||||||
import { MathUtil } from "@spt/utils/MathUtil";
|
import { MathUtil } from "@spt/utils/MathUtil";
|
||||||
import { ObjectId } from "@spt/utils/ObjectId";
|
import { ObjectId } from "@spt/utils/ObjectId";
|
||||||
import { RandomUtil } from "@spt/utils/RandomUtil";
|
import { RandomUtil } from "@spt/utils/RandomUtil";
|
||||||
@ -36,6 +37,7 @@ export class RepeatableQuestRewardGenerator {
|
|||||||
constructor(
|
constructor(
|
||||||
@inject("PrimaryLogger") protected logger: ILogger,
|
@inject("PrimaryLogger") protected logger: ILogger,
|
||||||
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
@inject("RandomUtil") protected randomUtil: RandomUtil,
|
||||||
|
@inject("HashUtil") protected hashUtil: HashUtil,
|
||||||
@inject("MathUtil") protected mathUtil: MathUtil,
|
@inject("MathUtil") protected mathUtil: MathUtil,
|
||||||
@inject("DatabaseService") protected databaseService: DatabaseService,
|
@inject("DatabaseService") protected databaseService: DatabaseService,
|
||||||
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
@inject("ItemHelper") protected itemHelper: ItemHelper,
|
||||||
@ -93,14 +95,18 @@ export class RepeatableQuestRewardGenerator {
|
|||||||
const rewards: IQuestRewards = { Started: [], Success: [], Fail: [] };
|
const rewards: IQuestRewards = { Started: [], Success: [], Fail: [] };
|
||||||
|
|
||||||
// Start reward index to keep track
|
// Start reward index to keep track
|
||||||
let rewardIndex = 0;
|
let rewardIndex = -1;
|
||||||
|
|
||||||
// Add xp reward
|
// Add xp reward
|
||||||
if (rewardParams.rewardXP > 0) {
|
if (rewardParams.rewardXP > 0) {
|
||||||
rewards.Success.push({
|
rewards.Success.push({
|
||||||
|
id: this.hashUtil.generate(),
|
||||||
|
unknown: false,
|
||||||
|
gameMode: [],
|
||||||
|
availableInGameEditions: [],
|
||||||
|
index: rewardIndex,
|
||||||
value: rewardParams.rewardXP,
|
value: rewardParams.rewardXP,
|
||||||
type: QuestRewardType.EXPERIENCE,
|
type: QuestRewardType.EXPERIENCE,
|
||||||
index: rewardIndex,
|
|
||||||
});
|
});
|
||||||
rewardIndex++;
|
rewardIndex++;
|
||||||
}
|
}
|
||||||
@ -163,6 +169,10 @@ export class RepeatableQuestRewardGenerator {
|
|||||||
// Add rep reward to rewards array
|
// Add rep reward to rewards array
|
||||||
if (rewardParams.rewardReputation > 0) {
|
if (rewardParams.rewardReputation > 0) {
|
||||||
const reward: IQuestReward = {
|
const reward: IQuestReward = {
|
||||||
|
id: this.hashUtil.generate(),
|
||||||
|
unknown: false,
|
||||||
|
gameMode: [],
|
||||||
|
availableInGameEditions: [],
|
||||||
target: traderId,
|
target: traderId,
|
||||||
value: rewardParams.rewardReputation,
|
value: rewardParams.rewardReputation,
|
||||||
type: QuestRewardType.TRADER_STANDING,
|
type: QuestRewardType.TRADER_STANDING,
|
||||||
@ -171,13 +181,17 @@ export class RepeatableQuestRewardGenerator {
|
|||||||
rewards.Success.push(reward);
|
rewards.Success.push(reward);
|
||||||
rewardIndex++;
|
rewardIndex++;
|
||||||
|
|
||||||
this.logger.debug(` Adding ${rewardParams.rewardReputation} trader reputation reward`);
|
this.logger.debug(`Adding: ${rewardParams.rewardReputation} ${traderId} trader reputation reward`);
|
||||||
}
|
}
|
||||||
|
|
||||||
// Chance of adding skill reward
|
// Chance of adding skill reward
|
||||||
if (this.randomUtil.getChance100(rewardParams.skillRewardChance * 100)) {
|
if (this.randomUtil.getChance100(rewardParams.skillRewardChance * 100)) {
|
||||||
const targetSkill = this.randomUtil.getArrayValue(questConfig.possibleSkillRewards);
|
const targetSkill = this.randomUtil.getArrayValue(questConfig.possibleSkillRewards);
|
||||||
const reward: IQuestReward = {
|
const reward: IQuestReward = {
|
||||||
|
id: this.hashUtil.generate(),
|
||||||
|
unknown: false,
|
||||||
|
gameMode: [],
|
||||||
|
availableInGameEditions: [],
|
||||||
target: targetSkill,
|
target: targetSkill,
|
||||||
value: rewardParams.skillPointReward,
|
value: rewardParams.skillPointReward,
|
||||||
type: QuestRewardType.SKILL,
|
type: QuestRewardType.SKILL,
|
||||||
@ -503,17 +517,23 @@ export class RepeatableQuestRewardGenerator {
|
|||||||
* @param preset Optional array of preset items
|
* @param preset Optional array of preset items
|
||||||
* @returns {object} Object of "Reward"-item-type
|
* @returns {object} Object of "Reward"-item-type
|
||||||
*/
|
*/
|
||||||
protected generateItemReward(tpl: string, count: number, index: number): IQuestReward {
|
protected generateItemReward(tpl: string, count: number, index: number, foundInRaid = true): IQuestReward {
|
||||||
const id = this.objectId.generate();
|
const id = this.objectId.generate();
|
||||||
const questRewardItem: IQuestReward = {
|
const questRewardItem: IQuestReward = {
|
||||||
|
id: this.hashUtil.generate(),
|
||||||
|
unknown: false,
|
||||||
|
gameMode: [],
|
||||||
|
availableInGameEditions: [],
|
||||||
|
index: index,
|
||||||
target: id,
|
target: id,
|
||||||
value: count,
|
value: count,
|
||||||
|
isEncoded: false,
|
||||||
|
findInRaid: foundInRaid,
|
||||||
type: QuestRewardType.ITEM,
|
type: QuestRewardType.ITEM,
|
||||||
index: index,
|
|
||||||
items: [],
|
items: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
const rootItem = { _id: id, _tpl: tpl, upd: { StackObjectsCount: count, SpawnedInSession: true } };
|
const rootItem = { _id: id, _tpl: tpl, upd: { StackObjectsCount: count, SpawnedInSession: foundInRaid } };
|
||||||
questRewardItem.items = [rootItem];
|
questRewardItem.items = [rootItem];
|
||||||
|
|
||||||
return questRewardItem;
|
return questRewardItem;
|
||||||
@ -528,13 +548,25 @@ export class RepeatableQuestRewardGenerator {
|
|||||||
* @param preset Optional array of preset items
|
* @param preset Optional array of preset items
|
||||||
* @returns {object} Object of "Reward"-item-type
|
* @returns {object} Object of "Reward"-item-type
|
||||||
*/
|
*/
|
||||||
protected generatePresetReward(tpl: string, count: number, index: number, preset?: IItem[]): IQuestReward {
|
protected generatePresetReward(
|
||||||
|
tpl: string,
|
||||||
|
count: number,
|
||||||
|
index: number,
|
||||||
|
preset?: IItem[],
|
||||||
|
foundInRaid = true,
|
||||||
|
): IQuestReward {
|
||||||
const id = this.objectId.generate();
|
const id = this.objectId.generate();
|
||||||
const questRewardItem: IQuestReward = {
|
const questRewardItem: IQuestReward = {
|
||||||
|
id: this.hashUtil.generate(),
|
||||||
|
unknown: false,
|
||||||
|
gameMode: [],
|
||||||
|
availableInGameEditions: [],
|
||||||
|
index: index,
|
||||||
target: id,
|
target: id,
|
||||||
value: count,
|
value: count,
|
||||||
|
isEncoded: false,
|
||||||
|
findInRaid: foundInRaid,
|
||||||
type: QuestRewardType.ITEM,
|
type: QuestRewardType.ITEM,
|
||||||
index: index,
|
|
||||||
items: [],
|
items: [],
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -544,6 +576,10 @@ export class RepeatableQuestRewardGenerator {
|
|||||||
this.logger.warning(`Root item of preset: ${tpl} not found`);
|
this.logger.warning(`Root item of preset: ${tpl} not found`);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (rootItem.upd) {
|
||||||
|
rootItem.upd.SpawnedInSession = foundInRaid;
|
||||||
|
}
|
||||||
|
|
||||||
questRewardItem.items = this.itemHelper.reparentItemAndChildren(rootItem, preset);
|
questRewardItem.items = this.itemHelper.reparentItemAndChildren(rootItem, preset);
|
||||||
questRewardItem.target = rootItem._id; // Target property and root items id must match
|
questRewardItem.target = rootItem._id; // Target property and root items id must match
|
||||||
|
|
||||||
@ -641,6 +677,6 @@ export class RepeatableQuestRewardGenerator {
|
|||||||
currency === Money.EUROS ? this.handbookHelper.fromRUB(rewardRoubles, Money.EUROS) : rewardRoubles;
|
currency === Money.EUROS ? this.handbookHelper.fromRUB(rewardRoubles, Money.EUROS) : rewardRoubles;
|
||||||
|
|
||||||
// Get chosen currency + amount and return
|
// Get chosen currency + amount and return
|
||||||
return this.generateItemReward(currency, rewardAmountToGivePlayer, rewardIndex);
|
return this.generateItemReward(currency, rewardAmountToGivePlayer, rewardIndex, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -160,8 +160,10 @@ export interface IQuestReward {
|
|||||||
loyaltyLevel?: number;
|
loyaltyLevel?: number;
|
||||||
/** Hideout area id */
|
/** Hideout area id */
|
||||||
traderId?: string;
|
traderId?: string;
|
||||||
|
isEncoded?: boolean;
|
||||||
unknown?: boolean;
|
unknown?: boolean;
|
||||||
findInRaid?: boolean;
|
findInRaid?: boolean;
|
||||||
|
gameMode?: string[];
|
||||||
/** Game editions whitelisted to get reward */
|
/** Game editions whitelisted to get reward */
|
||||||
availableInGameEditions?: string[];
|
availableInGameEditions?: string[];
|
||||||
/** Game editions blacklisted from getting reward */
|
/** Game editions blacklisted from getting reward */
|
||||||
|
@ -4,6 +4,12 @@ export interface IRepeatableQuest extends IQuest {
|
|||||||
changeCost: IChangeCost[];
|
changeCost: IChangeCost[];
|
||||||
changeStandingCost: number;
|
changeStandingCost: number;
|
||||||
sptRepatableGroupName: string;
|
sptRepatableGroupName: string;
|
||||||
|
acceptanceAndFinishingSource: string;
|
||||||
|
progressSource: string;
|
||||||
|
rankingModes: string[];
|
||||||
|
gameModes: string[];
|
||||||
|
arenaLocations: string[];
|
||||||
|
questStatus: IRepeatableQuestStatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
export interface IRepeatableQuestDatabase {
|
export interface IRepeatableQuestDatabase {
|
||||||
@ -13,6 +19,15 @@ export interface IRepeatableQuestDatabase {
|
|||||||
samples: ISampleQuests[];
|
samples: ISampleQuests[];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
export interface IRepeatableQuestStatus {
|
||||||
|
id: string;
|
||||||
|
uid: string;
|
||||||
|
qid: string;
|
||||||
|
startTime: number;
|
||||||
|
status: number;
|
||||||
|
statusTimers: any;
|
||||||
|
}
|
||||||
|
|
||||||
export interface IRepeatableTemplates {
|
export interface IRepeatableTemplates {
|
||||||
Elimination: IQuest;
|
Elimination: IQuest;
|
||||||
Completion: IQuest;
|
Completion: IQuest;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user