mirror of
https://github.com/thepeacockproject/Peacock
synced 2025-02-03 18:23:14 +01:00
Add Challenge completion and level completion percentage display (#79)
* Add challenges completion progress to responses * Update components/scoreHandler.ts Co-authored-by: Reece Dunham <me@rdil.rocks> Signed-off-by: moonysolari <118079569+moonysolari@users.noreply.github.com> Signed-off-by: moonysolari <118079569+moonysolari@users.noreply.github.com> Co-authored-by: Reece Dunham <me@rdil.rocks>
This commit is contained in:
parent
95b71b79e7
commit
b1dfdb8066
@ -226,11 +226,9 @@ export class ChallengeService extends ChallengeRegistry {
|
||||
/**
|
||||
* Get challenge lists sorted into groups.
|
||||
*
|
||||
* @param locationId The parent location's ID.
|
||||
* @param filter The filter to use.
|
||||
*/
|
||||
getGroupedChallengeLists(
|
||||
locationId: string,
|
||||
filter: ChallengeFilterOptions,
|
||||
): GroupIndexedChallengeLists {
|
||||
let challenges: [string, RegistryChallenge[]][] = []
|
||||
@ -285,7 +283,7 @@ export class ChallengeService extends ChallengeRegistry {
|
||||
|
||||
assert.ok(contractParentLocation)
|
||||
|
||||
return this.getGroupedChallengeLists(contractParentLocation, {
|
||||
return this.getGroupedChallengeLists({
|
||||
type: ChallengeFilterType.Contract,
|
||||
contractId: contractId,
|
||||
locationId: contract.Metadata.Location,
|
||||
@ -544,7 +542,7 @@ export class ChallengeService extends ChallengeRegistry {
|
||||
return []
|
||||
}
|
||||
|
||||
const forLocation = this.getGroupedChallengeLists(locationParentId, {
|
||||
const forLocation = this.getGroupedChallengeLists({
|
||||
type: ChallengeFilterType.ParentLocation,
|
||||
locationParentId,
|
||||
})
|
||||
@ -750,6 +748,40 @@ export class ChallengeService extends ChallengeRegistry {
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Counts the number of challenges and completed challenges in a GroupIndexedChallengeLists object.
|
||||
* @param challengeLists A GroupIndexedChallengeLists object, holding some challenges to be counted
|
||||
* @param userId The userId of the user to acquire completion information
|
||||
* @param gameVersion The version of the game
|
||||
* @returns An object with two properties: ChallengesCount and CompletedChallengesCount.
|
||||
*/
|
||||
countTotalNCompletedChallenges(
|
||||
challengeLists: GroupIndexedChallengeLists,
|
||||
userId: string,
|
||||
gameVersion: GameVersion,
|
||||
): { ChallengesCount: number; CompletedChallengesCount: number } {
|
||||
let challengesCount = 0
|
||||
let completedChallengesCount = 0
|
||||
for (const groupId in challengeLists) {
|
||||
const challenges = challengeLists[groupId]
|
||||
const challengeProgressionData = challenges.map((challengeData) =>
|
||||
this.getPersistentChallengeProgression(
|
||||
userId,
|
||||
challengeData.Id,
|
||||
gameVersion,
|
||||
),
|
||||
)
|
||||
challengesCount += challenges.length
|
||||
completedChallengesCount += challengeProgressionData.filter(
|
||||
(progressionData) => progressionData.Completed,
|
||||
).length
|
||||
}
|
||||
return {
|
||||
ChallengesCount: challengesCount,
|
||||
CompletedChallengesCount: completedChallengesCount,
|
||||
}
|
||||
}
|
||||
|
||||
private onChallengeCompleted(
|
||||
session: ContractSession,
|
||||
challenge: RegistryChallenge,
|
||||
|
@ -82,6 +82,7 @@ import { brotliDecompress } from "zlib"
|
||||
import assert from "assert"
|
||||
import { Response } from "express"
|
||||
import { MissionEndRequestQuery } from "./types/gameSchemas"
|
||||
import { ChallengeFilterType } from "./candle/challengeHelpers"
|
||||
|
||||
/**
|
||||
* An array of string arrays that contains the IDs of the featured contracts.
|
||||
@ -650,7 +651,7 @@ export class Controller {
|
||||
if (openCtJson) {
|
||||
return fastClone(openCtJson)
|
||||
}
|
||||
log(LogLevel.WARN, `Contract ${id} not found!`)
|
||||
log(LogLevel.TRACE, `Contract ${id} not found!`)
|
||||
return undefined
|
||||
}
|
||||
|
||||
@ -1177,14 +1178,24 @@ export function contractIdToHitObject(
|
||||
log(LogLevel.ERROR, "No UC due to previous error?")
|
||||
return undefined
|
||||
}
|
||||
const challenges = controller.challengeService.getGroupedChallengeLists({
|
||||
type: ChallengeFilterType.ParentLocation,
|
||||
locationParentId: parentLocation.Id,
|
||||
})
|
||||
const challengeCompletion =
|
||||
controller.challengeService.countTotalNCompletedChallenges(
|
||||
challenges,
|
||||
userId,
|
||||
gameVersion,
|
||||
)
|
||||
|
||||
return {
|
||||
Id: contract.Metadata.Id,
|
||||
UserCentricContract: userCentric,
|
||||
Location: parentLocation,
|
||||
SubLocation: subLocation,
|
||||
ChallengesCompleted: 0,
|
||||
ChallengesTotal: 0,
|
||||
ChallengesCompleted: challengeCompletion.CompletedChallengesCount,
|
||||
ChallengesTotal: challengeCompletion.ChallengesCount,
|
||||
LocationLevel: 1,
|
||||
LocationMaxLevel: 1,
|
||||
LocationCompletion: 0,
|
||||
|
@ -29,6 +29,7 @@ import type {
|
||||
import { controller } from "../controller"
|
||||
import { generateCompletionData } from "../contracts/dataGen"
|
||||
import { getUserData } from "components/databaseHandler"
|
||||
import { ChallengeFilterType } from "components/candle/challengeHelpers"
|
||||
|
||||
type GameFacingDestination = {
|
||||
ChallengeCompletion: {
|
||||
@ -53,6 +54,14 @@ export function getDestinationCompletion(
|
||||
req: RequestWithJwt,
|
||||
) {
|
||||
const userData = getUserData(req.jwt.unique_name, req.gameVersion)
|
||||
const challenges = controller.challengeService.getGroupedChallengeLists({
|
||||
type: ChallengeFilterType.ParentLocation,
|
||||
locationParentId: parent.Id,
|
||||
})
|
||||
|
||||
if (parent.Opportunities === undefined) {
|
||||
parent.Opportunities = 0
|
||||
}
|
||||
|
||||
let opportunityCompletedCount = 0
|
||||
for (const ms in userData.Extensions.opportunityprogression) {
|
||||
@ -60,21 +69,54 @@ export function getDestinationCompletion(
|
||||
opportunityCompletedCount++
|
||||
}
|
||||
}
|
||||
const challengeCompletion =
|
||||
controller.challengeService.countTotalNCompletedChallenges(
|
||||
challenges,
|
||||
userData.Id,
|
||||
req.gameVersion,
|
||||
)
|
||||
|
||||
return {
|
||||
ChallengeCompletion: {
|
||||
ChallengesCount: 0,
|
||||
CompletedChallengesCount: 0, // TODO: Hook this up to challenge counts.
|
||||
},
|
||||
ChallengeCompletion: challengeCompletion,
|
||||
OpportunityStatistics: {
|
||||
Count: parent.Opportunities,
|
||||
Completed: opportunityCompletedCount,
|
||||
},
|
||||
LocationCompletionPercent: 0,
|
||||
LocationCompletionPercent: getCompletionPercent(
|
||||
challengeCompletion.CompletedChallengesCount,
|
||||
challengeCompletion.ChallengesCount,
|
||||
opportunityCompletedCount,
|
||||
parent.Opportunities,
|
||||
),
|
||||
Location: parent,
|
||||
}
|
||||
}
|
||||
|
||||
export function getCompletionPercent(
|
||||
challengeDone: number,
|
||||
challengeTotal: number,
|
||||
opportunityDone: number,
|
||||
opportunityTotal: number,
|
||||
): number {
|
||||
if (challengeDone === undefined) {
|
||||
challengeDone = 0
|
||||
}
|
||||
if (challengeTotal === undefined) {
|
||||
challengeTotal = 0
|
||||
}
|
||||
if (opportunityDone === undefined) {
|
||||
opportunityDone = 0
|
||||
}
|
||||
if (opportunityTotal === undefined) {
|
||||
opportunityTotal = 0
|
||||
}
|
||||
const totalCompletables = challengeTotal + opportunityTotal
|
||||
const totalCompleted = challengeDone + opportunityDone
|
||||
return totalCompletables === 0
|
||||
? 0
|
||||
: (100 * totalCompleted) / totalCompletables
|
||||
}
|
||||
|
||||
export function destinationsMenu(req: RequestWithJwt): GameFacingDestination[] {
|
||||
const result: GameFacingDestination[] = []
|
||||
const locations = getVersionedConfig<PeacockLocationsData>(
|
||||
|
@ -25,11 +25,12 @@ import {
|
||||
xpRequiredForLevel,
|
||||
} from "./utils"
|
||||
import { contractSessions, getCurrentState } from "./eventHandler"
|
||||
import { getConfig } from "./configSwizzleManager"
|
||||
import { getConfig, getVersionedConfig } from "./configSwizzleManager"
|
||||
import { _theLastYardbirdScpc, controller } from "./controller"
|
||||
import type {
|
||||
ContractSession,
|
||||
MissionManifestObjective,
|
||||
PeacockLocationsData,
|
||||
RequestWithJwt,
|
||||
Seconds,
|
||||
} from "./types/types"
|
||||
@ -45,6 +46,8 @@ import { generateCompletionData } from "./contracts/dataGen"
|
||||
import { liveSplitManager } from "./livesplit/liveSplitManager"
|
||||
import { Playstyle, ScoringBonus, ScoringHeadline } from "./types/scoring"
|
||||
import { MissionEndRequestQuery } from "./types/gameSchemas"
|
||||
import { ChallengeFilterType } from "./candle/challengeHelpers"
|
||||
import { getCompletionPercent } from "./menus/destinations"
|
||||
|
||||
/**
|
||||
* Checks the criteria of each possible play-style, ranking them by scoring.
|
||||
@ -261,9 +264,36 @@ export async function missionEnd(
|
||||
? 0
|
||||
: sessionDetails.npcKills.size + sessionDetails.crowdNpcKills
|
||||
|
||||
// const allMissionStories = getConfig("MissionStories")
|
||||
// const missionStories = (contractData.Metadata.Opportunities || []).map((missionStoryId) => allMissionStories[missionStoryId])
|
||||
|
||||
const locations = getVersionedConfig<PeacockLocationsData>(
|
||||
"LocationsData",
|
||||
req.gameVersion,
|
||||
true,
|
||||
)
|
||||
const location = contractData.Metadata.Location
|
||||
const parent = locations.children[location].Properties.ParentLocation
|
||||
const locationChallenges =
|
||||
controller.challengeService.getGroupedChallengeLists({
|
||||
type: ChallengeFilterType.ParentLocation,
|
||||
locationParentId: parent,
|
||||
})
|
||||
const contractChallenges =
|
||||
controller.challengeService.getChallengesForContract(
|
||||
sessionDetails.contractId,
|
||||
req.gameVersion,
|
||||
)
|
||||
const challengeCompletion =
|
||||
controller.challengeService.countTotalNCompletedChallenges(
|
||||
locationChallenges,
|
||||
userData.Id,
|
||||
req.gameVersion,
|
||||
)
|
||||
const opportunities = contractData.Metadata.Opportunities
|
||||
const opportunityCount = opportunities ? opportunities.length : 0
|
||||
const opportunityCompleted = opportunities
|
||||
? opportunities.filter((ms) => (
|
||||
ms in userData.Extensions.opportunityprogression
|
||||
)).length
|
||||
: 0
|
||||
const result = {
|
||||
MissionReward: {
|
||||
LocationProgression: {
|
||||
@ -284,12 +314,7 @@ export async function missionEnd(
|
||||
.ProfileLevel,
|
||||
XPGain: 0,
|
||||
},
|
||||
Challenges: Object.values(
|
||||
controller.challengeService.getChallengesForContract(
|
||||
sessionDetails.contractId,
|
||||
req.gameVersion,
|
||||
),
|
||||
)
|
||||
Challenges: Object.values(contractChallenges)
|
||||
.flat()
|
||||
// FIXME: This behaviour may not be accurate to original server
|
||||
.filter(
|
||||
@ -319,19 +344,23 @@ export async function missionEnd(
|
||||
req.jwt.unique_name,
|
||||
req.gameVersion,
|
||||
),
|
||||
ChallengeCompletion: {
|
||||
ChallengesCount: 1,
|
||||
CompletedChallengesCount: 0,
|
||||
},
|
||||
ContractChallengeCompletion: {
|
||||
ChallengesCount: 1,
|
||||
CompletedChallengesCount: 0,
|
||||
},
|
||||
ChallengeCompletion: challengeCompletion,
|
||||
ContractChallengeCompletion:
|
||||
controller.challengeService.countTotalNCompletedChallenges(
|
||||
contractChallenges,
|
||||
userData.Id,
|
||||
req.gameVersion,
|
||||
),
|
||||
OpportunityStatistics: {
|
||||
Count: (contractData.Metadata.Opportunities || []).length,
|
||||
Completed: 0,
|
||||
Count: opportunityCount,
|
||||
Completed: opportunityCompleted,
|
||||
},
|
||||
LocationCompletionPercent: 0,
|
||||
LocationCompletionPercent: getCompletionPercent(
|
||||
challengeCompletion.CompletedChallengesCount,
|
||||
challengeCompletion.ChallengesCount,
|
||||
opportunityCompleted,
|
||||
opportunityCount,
|
||||
),
|
||||
},
|
||||
ScoreOverview: {
|
||||
XP: 0,
|
||||
|
Loading…
Reference in New Issue
Block a user