1
mirror of https://github.com/thepeacockproject/Peacock synced 2025-03-01 14:43:02 +01:00

Added support for Sniper locations on the score screen

Fixed issue with Mastery not leveling beyond level 1
Fixed issue where the score screen wouldn't show for locations without Mastery
This commit is contained in:
Lennard Fonteijn 2023-03-19 03:04:23 +01:00 committed by Reece Dunham
parent 4031779a91
commit 0eef121ac8
5 changed files with 212 additions and 53 deletions

@ -1190,10 +1190,6 @@ export class ChallengeService extends ChallengeRegistry {
const masteryData =
this.controller.masteryService.getMasteryPackage(parentLocationId)
if (!masteryData) {
return false
}
const parentLocationIdLowerCase = parentLocationId.toLocaleLowerCase()
//Update the Location data
@ -1209,23 +1205,25 @@ export class ChallengeService extends ChallengeRegistry {
parentLocationIdLowerCase
]
const maxLevel = masteryData.MaxLevel || DEFAULT_MASTERY_MAXLEVEL
const maxLevel = masteryData?.MaxLevel || DEFAULT_MASTERY_MAXLEVEL
locationData.Xp = clampValue(
locationData.Xp + masteryXp + actionXp,
0,
contract.Metadata.Type !== "evergreen"
? xpRequiredForLevel(maxLevel)
: xpRequiredForEvergreenLevel(maxLevel),
)
if (masteryData) {
locationData.Xp = clampValue(
locationData.Xp + masteryXp + actionXp,
0,
contract.Metadata.Type !== "evergreen"
? xpRequiredForLevel(maxLevel)
: xpRequiredForEvergreenLevel(maxLevel),
)
locationData.Level = clampValue(
contract.Metadata.Type !== "evergreen"
? levelForXp(locationData.Xp)
: evergreenLevelForXp(locationData.Xp),
1,
maxLevel,
)
locationData.Level = clampValue(
contract.Metadata.Type !== "evergreen"
? levelForXp(locationData.Xp)
: evergreenLevelForXp(locationData.Xp),
1,
maxLevel,
)
}
//Update the SubLocation data
const profileData = userProfile.Extensions.progression.PlayerProfileXP
@ -1244,13 +1242,16 @@ export class ChallengeService extends ChallengeRegistry {
profileData.Sublocations.push(foundSubLocation)
}
foundSubLocation.Xp = clampValue(
foundSubLocation.Xp + masteryXp,
0,
contract.Metadata.Type !== "evergreen"
? xpRequiredForLevel(maxLevel)
: xpRequiredForEvergreenLevel(maxLevel),
)
if (masteryData) {
foundSubLocation.Xp = clampValue(
foundSubLocation.Xp + masteryXp,
0,
contract.Metadata.Type !== "evergreen"
? xpRequiredForLevel(maxLevel)
: xpRequiredForEvergreenLevel(maxLevel),
)
}
foundSubLocation.ActionXp += actionXp
//Update the EvergreenLevel with the latest Mastery Level

@ -27,6 +27,7 @@ import {
isObjectiveActive,
levelForXp,
PEACOCKVERSTRING,
SNIPER_LEVEL_INFO,
xpRequiredForEvergreenLevel,
xpRequiredForLevel,
} from "./utils"
@ -699,11 +700,16 @@ export async function missionEnd(
const masteryData =
controller.masteryService.getMasteryPackage(locationParentId)
const maxLevel = masteryData.MaxLevel || DEFAULT_MASTERY_MAXLEVEL
let maxLevel = 1
let locationLevelInfo = [0]
let locationLevelInfo = Array.from({ length: maxLevel }, (_, i) => {
return xpRequiredForLevel(i + 1)
})
if (masteryData) {
maxLevel = masteryData.MaxLevel || DEFAULT_MASTERY_MAXLEVEL
Array.from({ length: maxLevel }, (_, i) => {
return xpRequiredForLevel(i + 1)
})
}
const completionData = generateCompletionData(
contractData.Metadata.Location,
@ -752,6 +758,17 @@ export async function missionEnd(
timeTotal,
)
let contractScore = {
Total: calculateScoreResult.scoreWithBonus,
AchievedMasteries: calculateScoreResult.achievedMasteries,
AwardedBonuses: calculateScoreResult.awardedBonuses,
TotalNoMultipliers: calculateScoreResult.score,
TimeUsedSecs: timeTotal,
StarCount: calculateScoreResult.stars,
FailedBonuses: calculateScoreResult.failedBonuses,
SilentAssassin: calculateScoreResult.silentAssassin,
}
//Evergreen
const evergreenData: MissionEndEvergreen = <MissionEndEvergreen>{
PayoutsCompleted: [],
@ -851,6 +868,120 @@ export async function missionEnd(
}
calculateScoreResult.silentAssassin = false
//Overide the calculated score
calculateScoreResult.stars = undefined
}
//Sniper
let unlockableProgression = undefined
let sniperChallengeScore = undefined
//TODO: Calculate proper Sniper XP and Score
//TODO: Move most of this to its own calculateSniperScore function
if (contractData.Metadata.Type === "sniper") {
const sniperLoadouts = getConfig("SniperLoadouts", true)
const mainUnlockableProperties =
sniperLoadouts[contractData.Metadata.Location][
req.query.masteryUnlockableId
].MainUnlockable.Properties
unlockableProgression = {
LevelInfo: SNIPER_LEVEL_INFO,
XP: SNIPER_LEVEL_INFO[SNIPER_LEVEL_INFO.length - 1],
Level: SNIPER_LEVEL_INFO.length,
XPGain: 0,
Id: mainUnlockableProperties.ProgressionKey,
Name: mainUnlockableProperties.Name,
}
sniperChallengeScore = {
FinalScore: 112000,
BaseScore: 112000,
TotalChallengeMultiplier: 1.0,
BulletsMissed: 0,
BulletsMissedPenalty: 0,
TimeTaken: timeTotal,
TimeBonus: 0,
SilentAssassin: false,
SilentAssassinBonus: 0,
SilentAssassinMultiplier: 1.0,
}
//Override the contract score
contractScore = undefined
//Override the playstyle
playstyle = undefined
//Override the calculated score
const timeMinutes = Math.floor(timeTotal / 60)
const timeSeconds = Math.floor(timeTotal % 60)
const timeMiliseconds = Math.floor(
((timeTotal % 60) - timeSeconds) * 1000,
)
const defaultHeadline: Partial<ScoringHeadline> = {
type: "summary",
count: "",
scoreIsFloatingType: false,
fractionNumerator: 0,
fractionDenominator: 0,
scoreTotal: 0,
}
const headlines = [
{
headline: "UI_SNIPERSCORING_SUMMARY_BASESCORE",
scoreTotal: 112000,
},
{
headline: "UI_SNIPERSCORING_SUMMARY_BULLETS_MISSED_PENALTY",
scoreTotal: 0,
},
{
headline: "UI_SNIPERSCORING_SUMMARY_TIME_BONUS",
count: `${String(timeMinutes).padStart(2, "0")}:${String(
timeSeconds,
).padStart(2, "0")}.${String(timeMiliseconds).padStart(
3,
"0",
)}`,
scoreTotal: 0,
},
{
headline: "UI_SNIPERSCORING_SUMMARY_SILENT_ASSASIN_BONUS",
scoreTotal: 0,
},
{
headline: "UI_SNIPERSCORING_SUMMARY_SUBTOTAL",
scoreTotal: 112000,
},
{
headline: "UI_SNIPERSCORING_SUMMARY_CHALLENGE_MULTIPLIER",
scoreIsFloatingType: true,
scoreTotal: 1.0,
},
{
headline: "UI_SNIPERSCORING_SUMMARY_SILENT_ASSASIN_MULTIPLIER",
scoreIsFloatingType: true,
scoreTotal: 1.0,
},
{
type: "total",
headline: "UI_SNIPERSCORING_SUMMARY_TOTAL",
scoreTotal: 112000,
},
]
calculateScoreResult.stars = undefined
calculateScoreResult.scoringHeadlines = headlines.map((e) => {
return Object.assign(
Object.assign({}, defaultHeadline),
e,
) as ScoringHeadline
})
}
//Drops
@ -864,13 +995,16 @@ export async function missionEnd(
req.jwt.unique_name,
) as MasteryData[]
drops = masteryData[0].Drops.filter(
(e) => e.Level > oldLocationLevel && e.Level <= newLocationLevel,
).map((e) => {
return {
Unlockable: e.Unlockable,
}
})
if (masteryData) {
drops = masteryData[0].Drops.filter(
(e) =>
e.Level > oldLocationLevel && e.Level <= newLocationLevel,
).map((e) => {
return {
Unlockable: e.Unlockable,
}
})
}
}
//Setup the result
@ -883,7 +1017,7 @@ export async function missionEnd(
Completion: completionData.Completion,
//NOTE: Official makes this 0 if maximum Mastery is reached
XPGain: completionData.Level === maxLevel ? 0 : totalXpGain,
HideProgression: masteryData.HideProgression || false,
HideProgression: masteryData?.HideProgression || false,
},
ProfileProgression: {
LevelInfo: profileLevelInfo,
@ -896,6 +1030,7 @@ export async function missionEnd(
Drops: drops,
//TODO: Do these exist? Appears to be optional.
OpportunityRewards: [],
UnlockableProgression: unlockableProgression,
CompletionData: completionData,
ChallengeCompletion: locationChallengeCompletion,
ContractChallengeCompletion: contractChallengeCompletion,
@ -912,23 +1047,18 @@ export async function missionEnd(
//NOTE: Official appears to always make this 0
XPGain: 0,
ChallengesCompleted: justTickedChallenges,
LocationHideProgression: masteryData.HideProgression || false,
LocationHideProgression: masteryData?.HideProgression || false,
ProdileId1: req.jwt.unique_name,
stars: calculateScoreResult.stars,
ScoreDetails: {
Headlines: calculateScoreResult.scoringHeadlines,
},
ContractScore: {
Total: calculateScoreResult.scoreWithBonus,
AchievedMasteries: calculateScoreResult.achievedMasteries,
AwardedBonuses: calculateScoreResult.awardedBonuses,
TotalNoMultipliers: calculateScoreResult.score,
TimeUsedSecs: timeTotal,
StarCount: calculateScoreResult.stars,
FailedBonuses: calculateScoreResult.failedBonuses,
SilentAssassin: calculateScoreResult.silentAssassin,
},
SilentAssassin: calculateScoreResult.silentAssassin,
ContractScore: contractScore,
SniperChallengeScore: sniperChallengeScore,
SilentAssassin:
contractScore?.SilentAssassin ||
sniperChallengeScore?.silentAssassin ||
false,
//TODO: Use data from the leaderboard?
NewRank: 1,
RankCount: 1,

@ -18,6 +18,7 @@
export type MissionEndRequestQuery = Partial<{
contractSessionId: string
masteryUnlockableId?: string
}>
/**

@ -74,6 +74,14 @@ export interface MissionEndResponse {
Challenges: MissionEndChallenge[]
Drops: MissionEndDrop[]
OpportunityRewards: unknown[] //?
UnlockableProgression?: {
LevelInfo: number[]
XP: number
Level: number
XPGain: number
Id: string
Name: string
}
CompletionData: CompletionData
ChallengeCompletion: {
ChallengesCount: number
@ -97,11 +105,11 @@ export interface MissionEndResponse {
ChallengesCompleted: number
LocationHideProgression: boolean
ProdileId1?: string
stars: number
stars?: number
ScoreDetails: {
Headlines: ScoringHeadline[]
}
ContractScore: {
ContractScore?: {
Total: number
AchievedMasteries: MissionEndAchievedMastery[]
AwardedBonuses: ScoringBonus[]
@ -111,6 +119,18 @@ export interface MissionEndResponse {
FailedBonuses: ScoringBonus[]
SilentAssassin: boolean
}
SniperChallengeScore?: {
FinalScore: number
BaseScore: number
TotalChallengeMultiplier: number
BulletsMissed: number
BulletsMissedPenalty: number
TimeTaken: number
TimeBonus: number
SilentAssassin: boolean
SilentAssassinBonus: number
SilentAssassinMultiplier: number
}
SilentAssassin: boolean
NewRank: number
RankCount: number

@ -139,7 +139,7 @@ export function getMaxProfileLevel(gameVersion: GameVersion): number {
* Minimum level returned is 1.
*/
export function levelForXp(xp: number): number {
return Math.min(1, Math.floor(xp / XP_PER_LEVEL) + 1)
return Math.max(1, Math.floor(xp / XP_PER_LEVEL) + 1)
}
/**
@ -182,6 +182,13 @@ export function xpRequiredForEvergreenLevel(level: number): number {
return EVERGREEN_LEVEL_INFO[level - 1]
}
//TODO: Determine some mathematical function
export const SNIPER_LEVEL_INFO: number[] = [
0, 50000, 150000, 500000, 1000000, 1700000, 2500000, 3500000, 5000000,
7000000, 9500000, 12500000, 16000000, 20000000, 25000000, 31000000,
38000000, 47000000, 58000000, 70000000,
]
/**
* Clamps the given value between a minimum and maximum value
*/