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:
parent
4031779a91
commit
0eef121ac8
components
@ -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
|
||||
*/
|
||||
|
Loading…
x
Reference in New Issue
Block a user