-
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add match stats to the series output (#9)
Co-authored-by: Matthew Lee <[email protected]>
- Loading branch information
1 parent
5819f46
commit b38b0d0
Showing
25 changed files
with
565 additions
and
47 deletions.
There are no files selected for viewing
File renamed without changes.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed } from "./base-match-embed.mjs"; | ||
|
||
export class AttritionMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerAttrition> { | ||
override getPlayerObjectiveStats(): Map<string, string> { | ||
return new Map([]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,106 @@ | ||
import { GameVariantCategory, MatchStats } from "halo-infinite-api"; | ||
import { HaloService } from "../../../services/halo/halo.mjs"; | ||
import { EmbedBuilder } from "discord.js"; | ||
import { Preconditions } from "../../../base/preconditions.mjs"; | ||
|
||
export type PlayerStats<TCategory extends GameVariantCategory> = | ||
MatchStats<TCategory>["Players"][0]["PlayerTeamStats"][0]["Stats"]; | ||
|
||
export abstract class BaseMatchEmbed<TCategory extends GameVariantCategory> { | ||
constructor(protected readonly haloService: HaloService) {} | ||
|
||
protected abstract getPlayerObjectiveStats(stats: PlayerStats<TCategory>): Map<string, string>; | ||
|
||
protected getPlayerSlayerStats(stats: PlayerStats<TCategory>): Map<string, string> { | ||
const { CoreStats } = stats; | ||
return new Map([ | ||
["Kills", CoreStats.Kills.toString()], | ||
["Deaths", CoreStats.Deaths.toString()], | ||
["Assists", CoreStats.Assists.toString()], | ||
["KDA", CoreStats.KDA.toString()], | ||
["Headshot kills", CoreStats.HeadshotKills.toString()], | ||
["Shots H:F", `${CoreStats.ShotsHit.toString()}:${CoreStats.ShotsFired.toString()}`], | ||
["Accuracy", `${CoreStats.Accuracy.toString()}%`], | ||
["Damage D:T", `${CoreStats.DamageDealt.toString()}:${CoreStats.DamageTaken.toString()}`], | ||
["Av life duration", this.haloService.getReadableDuration(CoreStats.AverageLifeDuration)], | ||
["Av damage/life", (CoreStats.DamageDealt / CoreStats.Deaths).toFixed(2)], | ||
]); | ||
} | ||
|
||
async getEmbed(match: MatchStats, players: Map<string, string>) { | ||
const gameTypeAndMap = await this.haloService.getGameTypeAndMap(match); | ||
|
||
const embed = new EmbedBuilder() | ||
.setTitle(gameTypeAndMap) | ||
.setURL(`https://halodatahive.com/Infinite/Match/${match.MatchId}`); | ||
|
||
for (const team of match.Teams) { | ||
embed.addFields({ | ||
name: this.haloService.getTeamName(team.TeamId), | ||
value: `Team Score: ${team.Stats.CoreStats.Score.toString()}`, | ||
inline: false, | ||
}); | ||
|
||
const teamPlayers = match.Players.filter((player) => | ||
player.PlayerTeamStats.find((teamStats) => teamStats.TeamId === team.TeamId), | ||
).sort((a, b) => { | ||
if (a.Rank - b.Rank !== 0) { | ||
return a.Rank - b.Rank; | ||
} | ||
|
||
const aStats = Preconditions.checkExists( | ||
a.PlayerTeamStats.find((teamStats) => teamStats.TeamId === team.TeamId), | ||
); | ||
const bStats = Preconditions.checkExists( | ||
b.PlayerTeamStats.find((teamStats) => teamStats.TeamId === team.TeamId), | ||
); | ||
return aStats.Stats.CoreStats.Score - bStats.Stats.CoreStats.Score; | ||
}); | ||
|
||
let playerFields = []; | ||
for (const teamPlayer of teamPlayers) { | ||
const playerXuid = this.haloService.getPlayerXuid(teamPlayer); | ||
const playerGamertag = Preconditions.checkExists(players.get(playerXuid)); | ||
const playerStats = Preconditions.checkExists( | ||
teamPlayer.PlayerTeamStats.find((teamStats) => teamStats.TeamId === team.TeamId), | ||
"Unable to match player to team", | ||
) as MatchStats<TCategory>["Players"][0]["PlayerTeamStats"][0]; | ||
|
||
const { | ||
Stats: { CoreStats: coreStats }, | ||
} = playerStats; | ||
|
||
const outputStats = [ | ||
`Rank: ${teamPlayer.Rank.toString()}`, | ||
`Score: ${coreStats.Score.toString()}`, | ||
...this.playerStatsToFields(this.getPlayerSlayerStats(playerStats.Stats)), | ||
...this.playerStatsToFields(this.getPlayerObjectiveStats(playerStats.Stats)), | ||
]; | ||
playerFields.push({ | ||
name: playerGamertag, | ||
value: `\`\`\`${outputStats.join("\n")}\`\`\``, | ||
inline: true, | ||
}); | ||
|
||
// If two players are added, or if it's the last player, push to embed and reset | ||
if (playerFields.length === 2 || teamPlayer === teamPlayers[teamPlayers.length - 1]) { | ||
embed.addFields(playerFields); | ||
playerFields = []; | ||
|
||
// Adds a new row | ||
embed.addFields({ | ||
name: "\n", | ||
value: "\n", | ||
inline: false, | ||
}); | ||
} | ||
} | ||
} | ||
|
||
return embed; | ||
} | ||
|
||
private playerStatsToFields(playerStats: Map<string, string>): string[] { | ||
return Array.from(playerStats.entries()).map(([key, value]) => `${key}: ${value}`); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed, PlayerStats } from "./base-match-embed.mjs"; | ||
|
||
export class CtfMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerCtf> { | ||
override getPlayerObjectiveStats(stats: PlayerStats<GameVariantCategory.MultiplayerCtf>): Map<string, string> { | ||
return new Map([ | ||
["Captures", stats.CaptureTheFlagStats.FlagCaptures.toString()], | ||
["Captures assists", stats.CaptureTheFlagStats.FlagCaptureAssists.toString()], | ||
["Carrier time", this.haloService.getReadableDuration(stats.CaptureTheFlagStats.TimeAsFlagCarrier)], | ||
["Grabs", stats.CaptureTheFlagStats.FlagGrabs.toString()], | ||
["Returns", stats.CaptureTheFlagStats.FlagReturns.toString()], | ||
["Carriers killed", stats.CaptureTheFlagStats.FlagCarriersKilled.toString()], | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,17 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed, PlayerStats } from "./base-match-embed.mjs"; | ||
|
||
export class EliminationMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerElimination> { | ||
override getPlayerObjectiveStats( | ||
stats: PlayerStats<GameVariantCategory.MultiplayerElimination>, | ||
): Map<string, string> { | ||
return new Map([ | ||
["Eliminations", stats.EliminationStats.Eliminations.toString()], | ||
["Elimination assists", stats.EliminationStats.EliminationAssists.toString()], | ||
["Allies revived", stats.EliminationStats.AlliesRevived.toString()], | ||
["Rounds Survived", stats.EliminationStats.RoundsSurvived.toString()], | ||
["Times revived by ally", stats.EliminationStats.TimesRevivedByAlly.toString()], | ||
["Enemy revives denied", stats.EliminationStats.EnemyRevivesDenied.toString()], | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed } from "./base-match-embed.mjs"; | ||
|
||
export class EscalationMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerEscalation> { | ||
override getPlayerObjectiveStats(): Map<string, string> { | ||
return new Map(); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,14 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed, PlayerStats } from "./base-match-embed.mjs"; | ||
|
||
export class ExtractionMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerExtraction> { | ||
override getPlayerObjectiveStats(stats: PlayerStats<GameVariantCategory.MultiplayerExtraction>): Map<string, string> { | ||
return new Map([ | ||
["Successful extractions", stats.ExtractionStats.SuccessfulExtractions.toString()], | ||
["Extraction initiations completed", stats.ExtractionStats.ExtractionInitiationsCompleted.toString()], | ||
["Extraction initiations denied", stats.ExtractionStats.ExtractionInitiationsDenied.toString()], | ||
["Extraction conversions completed", stats.ExtractionStats.ExtractionConversionsCompleted.toString()], | ||
["Extraction conversions denied", stats.ExtractionStats.ExtractionConversionsDenied.toString()], | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed } from "./base-match-embed.mjs"; | ||
|
||
export class FiestaMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerFiesta> { | ||
override getPlayerObjectiveStats(): Map<string, string> { | ||
return new Map([]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,23 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed, PlayerStats } from "./base-match-embed.mjs"; | ||
|
||
export class FirefightMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerFirefight> { | ||
override getPlayerObjectiveStats(stats: PlayerStats<GameVariantCategory.MultiplayerFirefight>): Map<string, string> { | ||
return new Map([ | ||
["Eliminations", stats.EliminationStats.Eliminations.toString()], | ||
["Elimination assists", stats.EliminationStats.EliminationAssists.toString()], | ||
["Allies revived", stats.EliminationStats.AlliesRevived.toString()], | ||
["Rounds Survived", stats.EliminationStats.RoundsSurvived.toString()], | ||
["Times revived by ally", stats.EliminationStats.TimesRevivedByAlly.toString()], | ||
["Enemy revives denied", stats.EliminationStats.EnemyRevivesDenied.toString()], | ||
["Boss kills", stats.PveStats.BossKills.toString()], | ||
["Hunter kills", stats.PveStats.HunterKills.toString()], | ||
["Elite kills", stats.PveStats.EliteKills.toString()], | ||
["Jackal kills", stats.PveStats.JackalKills.toString()], | ||
["Grunt kills", stats.PveStats.GruntKills.toString()], | ||
["Brute kills", stats.PveStats.BruteKills.toString()], | ||
["Sentinel kills", stats.PveStats.SentinelKills.toString()], | ||
["Skimmer kills", stats.PveStats.SkimmerKills.toString()], | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed } from "./base-match-embed.mjs"; | ||
|
||
export class GrifballMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerGrifball> { | ||
override getPlayerObjectiveStats(): Map<string, string> { | ||
return new Map([]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,19 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed, PlayerStats } from "./base-match-embed.mjs"; | ||
|
||
export class InfectionMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerInfection> { | ||
override getPlayerObjectiveStats(stats: PlayerStats<GameVariantCategory.MultiplayerInfection>): Map<string, string> { | ||
return new Map([ | ||
["Alphas killed", stats.InfectionSTats.AlphasKilled.toString()], | ||
["Infected killed", stats.InfectionSTats.InfectedKilled.toString()], | ||
["Kills as last spartan standing", stats.InfectionSTats.KillsAsLastSpartanStanding.toString()], | ||
["Rounds survived as spartan", stats.InfectionSTats.RoundsSurvivedAsSpartan.toString()], | ||
[ | ||
"Time as last spartan standing", | ||
this.haloService.getReadableDuration(stats.InfectionSTats.TimeAsLastSpartanStanding), | ||
], | ||
["Spartans infected", stats.InfectionSTats.SpartansInfected.toString()], | ||
["Spartans infected as alpha", stats.InfectionSTats.SpartansInfectedAsAlpha.toString()], | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed, PlayerStats } from "./base-match-embed.mjs"; | ||
|
||
export class KOTHMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerKingOfTheHill> { | ||
override getPlayerObjectiveStats( | ||
stats: PlayerStats<GameVariantCategory.MultiplayerKingOfTheHill>, | ||
): Map<string, string> { | ||
return new Map([ | ||
["Captures", stats.ZonesStats.StrongholdCaptures.toString()], | ||
["Occupation time", this.haloService.getReadableDuration(stats.ZonesStats.StrongholdOccupationTime)], | ||
["Secures", stats.ZonesStats.StrongholdSecures.toString()], | ||
["Offensive kills", stats.ZonesStats.StrongholdOffensiveKills.toString()], | ||
["Defensive kills", stats.ZonesStats.StrongholdDefensiveKills.toString()], | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed } from "./base-match-embed.mjs"; | ||
|
||
export class LandGrabMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerLandGrab> { | ||
override getPlayerObjectiveStats(): Map<string, string> { | ||
return new Map([]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed } from "./base-match-embed.mjs"; | ||
|
||
export class MinigameMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerMinigame> { | ||
override getPlayerObjectiveStats(): Map<string, string> { | ||
return new Map([]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,11 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed, PlayerStats } from "./base-match-embed.mjs"; | ||
|
||
export class OddballMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerOddball> { | ||
override getPlayerObjectiveStats(stats: PlayerStats<GameVariantCategory.MultiplayerOddball>): Map<string, string> { | ||
return new Map([ | ||
["Total time as carrier", this.haloService.getReadableDuration(stats.OddballStats.TimeAsSkullCarrier)], | ||
["Longest time as carrier", this.haloService.getReadableDuration(stats.OddballStats.LongestTimeAsSkullCarrier)], | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed } from "./base-match-embed.mjs"; | ||
|
||
export class SlayerMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerSlayer> { | ||
override getPlayerObjectiveStats(): Map<string, string> { | ||
return new Map([]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,15 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed, PlayerStats } from "./base-match-embed.mjs"; | ||
|
||
export class StockpileMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerStockpile> { | ||
override getPlayerObjectiveStats(stats: PlayerStats<GameVariantCategory.MultiplayerStockpile>): Map<string, string> { | ||
return new Map([ | ||
["Power seeds deposited", stats.StockpileStats.PowerSeedsDeposited.toString()], | ||
["Power seeds stolen", stats.StockpileStats.PowerSeedsStolen.toString()], | ||
["Kills as power seed carrier", stats.StockpileStats.KillsAsPowerSeedCarrier.toString()], | ||
["Power seed carriers killed", stats.StockpileStats.PowerSeedCarriersKilled.toString()], | ||
["Time as power seed carrier", this.haloService.getReadableDuration(stats.StockpileStats.TimeAsPowerSeedCarrier)], | ||
["Time as power seed driver", this.haloService.getReadableDuration(stats.StockpileStats.TimeAsPowerSeedDriver)], | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,16 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed, PlayerStats } from "./base-match-embed.mjs"; | ||
|
||
export class StrongholdsMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerStrongholds> { | ||
override getPlayerObjectiveStats( | ||
stats: PlayerStats<GameVariantCategory.MultiplayerStrongholds>, | ||
): Map<string, string> { | ||
return new Map([ | ||
["Captures", stats.ZonesStats.StrongholdCaptures.toString()], | ||
["Occupation time", this.haloService.getReadableDuration(stats.ZonesStats.StrongholdOccupationTime)], | ||
["Secures", stats.ZonesStats.StrongholdSecures.toString()], | ||
["Offensive kills", stats.ZonesStats.StrongholdOffensiveKills.toString()], | ||
["Defensive kills", stats.ZonesStats.StrongholdDefensiveKills.toString()], | ||
]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed } from "./base-match-embed.mjs"; | ||
|
||
export class TotalControlMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerTotalControl> { | ||
override getPlayerObjectiveStats(): Map<string, string> { | ||
return new Map([]); | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,8 @@ | ||
import { GameVariantCategory } from "halo-infinite-api"; | ||
import { BaseMatchEmbed } from "./base-match-embed.mjs"; | ||
|
||
export class UnknownMatchEmbed extends BaseMatchEmbed<GameVariantCategory.MultiplayerTotalControl> { | ||
override getPlayerObjectiveStats(): Map<string, string> { | ||
return new Map([]); | ||
} | ||
} |
Oops, something went wrong.