mirror of
https://github.com/Sendouc/sendou.ink.git
synced 2026-08-04 11:22:40 -05:00
* Tables * Clocks * Maplist preference selector * Fix SSR * Nav icon * RankedOrScrim * Map pool * Create group * Redirect logic * Persist map pool * Advance from preparing page * Rename query * Fix merge * Fix migration order * Seed groups * Find looking groups SQL * Renders something * More UI work * Back to 30min * Likes/dislikes * Always return own group * Fix like order * 3 tc/rm/cb -> 2 * Show only 3 weapons * Pass group size * Handle both liked and liked by same group * Fix SQL * Group preference frontend work * Morphing * Styling * Don't show group controls if not manager * Give/remove manager * Leave group * Leave with confirm * Delete likes when morphing groups * Clocks consistency * Remove bad invariant * Persist settings to local storage * Fix initial value flashing * Fix never resolving loading indicator * REFRESH_GROUP * Flip animations * Tweaks * Auto refresh logic * Groups of 4 seed * Reduce throwing * Load full groups initial * Create match * Match UI initial * Score reporter initial * Push footer down on match page * Score reporter knows when set ended * Score reporting untested * Show score after report * Align better * Look again with same group functionality * More migrations * Team on match page * Show confirmer before reporting score * Report weapons * Report weapos again by admin + skill changing * Handle no tiebreaker given to MapPool * Remove unranked * Remove support for "team id skill" * no-wrap -> nowrap * Preparing page work * Use common GroupCard component * Add some metas * MemberAdder in looking page * Fix GroupCard actions * Fix SZ only map list including other modes * Add season info * Prompt login * Joining team * Manage group on preparing page * Manage group on preparing page * Seed past matches * Add to seed * No map list preference when full group + fix expiry * Fix skill matchesCount calculation * Tiers initial work * Some progress on tiers * Tiering logic * MMR in group cards * Name to challenge * Team MMR * Big team rank icons * Adjust todos * Match score report with confirm * Allow regular members to report score * Handle reporting weapons edge cases * Add tier images * Improve GroupCard spacing * Refactor looking page * Looking mobile UI * Calculate skill only for current season * Divide groups visually when reporting weapons * Fix match page weapons sorting * Add cache to user skills+tier calculation * Admin report match score * Initial leaderboard * Cached leaderboard * Weapon category lb's * Populate SkillTeamUser in SendouQ * Team leaderboard filtered down * Add TODOs * Seasons initlal * Season weapons initial * Weapons stylized * Show rest weapons as + * Hide peak if same as current * Load matches SQL initial * Season matches UI initial * Take user id in account * Add weapons * Paginated matches * Fix pages count logic * Scroll top on data change * Day headers for matches * Link from user page to user seasons page * Summarize maps + ui initial * Map stats * Player info tabs * MMR chart * Chart adjustments * Handle basing team MMR on player MMR * Set initial MMR * Add info about discord to match page * Season support to tournaments * Get tournament skills as well for the graph * WIP * New team rating logic + misc other * tiered -> tiered.server * Update season starting time * TODOs * Add rules page * Hide elements correctly when off-season * Fix crash when only one player with skill * How-to video * Fix StartRank showing when not logged in * Make user leaderboard the default * Make Skill season non-nullable * Add suggested pass to match * Add rule * identifierToUserIds helper * Fix tiers not showing
151 lines
3.7 KiB
TypeScript
151 lines
3.7 KiB
TypeScript
import type { MapResult, PlayerResult } from "~/db/types";
|
|
import type { MatchById } from "../queries/findMatchById.server";
|
|
import { previousOrCurrentSeason } from "~/features/mmr/season";
|
|
import invariant from "tiny-invariant";
|
|
import { winnersArrayToWinner } from "../q-utils";
|
|
|
|
export function summarizeMaps({
|
|
match,
|
|
winners,
|
|
members,
|
|
}: {
|
|
match: MatchById;
|
|
winners: ("ALPHA" | "BRAVO")[];
|
|
members: { id: number; groupId: number }[];
|
|
}) {
|
|
const season = previousOrCurrentSeason(new Date())?.nth;
|
|
invariant(typeof season === "number", "No ranked season for skills");
|
|
|
|
const result: Array<MapResult> = [];
|
|
|
|
const playedMaps = match.mapList.slice(0, winners.length);
|
|
|
|
for (const [i, map] of playedMaps.entries()) {
|
|
const winnerSide = winners[i];
|
|
const winnerGroupId =
|
|
winnerSide === "ALPHA" ? match.alphaGroupId : match.bravoGroupId;
|
|
|
|
const winnerPlayers = members.filter((p) => p.groupId === winnerGroupId);
|
|
const loserPlayers = members.filter((p) => p.groupId !== winnerGroupId);
|
|
|
|
for (const winner of winnerPlayers) {
|
|
result.push({
|
|
userId: winner.id,
|
|
wins: 1,
|
|
losses: 0,
|
|
mode: map.mode,
|
|
stageId: map.stageId,
|
|
season,
|
|
});
|
|
}
|
|
|
|
for (const loser of loserPlayers) {
|
|
result.push({
|
|
userId: loser.id,
|
|
wins: 0,
|
|
losses: 1,
|
|
mode: map.mode,
|
|
stageId: map.stageId,
|
|
season,
|
|
});
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
export function summarizePlayerResults({
|
|
match,
|
|
winners,
|
|
members,
|
|
}: {
|
|
match: MatchById;
|
|
winners: ("ALPHA" | "BRAVO")[];
|
|
members: { id: number; groupId: number }[];
|
|
}) {
|
|
const season = previousOrCurrentSeason(new Date())?.nth;
|
|
invariant(typeof season === "number", "No ranked season for skills");
|
|
|
|
const result: Array<PlayerResult> = [];
|
|
|
|
const addMapResult = ({
|
|
outcome,
|
|
type,
|
|
ownerUserId,
|
|
otherUserId,
|
|
}: {
|
|
outcome: "win" | "loss";
|
|
type: "MATE" | "ENEMY";
|
|
ownerUserId: number;
|
|
otherUserId: number;
|
|
}) => {
|
|
const existing = result.find(
|
|
(r) => r.ownerUserId === ownerUserId && r.otherUserId === otherUserId
|
|
);
|
|
if (existing) {
|
|
if (outcome === "win") {
|
|
existing.mapWins++;
|
|
} else existing.mapLosses++;
|
|
} else {
|
|
result.push({
|
|
ownerUserId,
|
|
otherUserId,
|
|
type,
|
|
mapWins: outcome === "win" ? 1 : 0,
|
|
mapLosses: outcome === "win" ? 0 : 1,
|
|
season,
|
|
setLosses: 0,
|
|
setWins: 0,
|
|
});
|
|
}
|
|
};
|
|
|
|
for (const winner of winners) {
|
|
for (const member of members) {
|
|
for (const member2 of members) {
|
|
if (member.id === member2.id) continue;
|
|
|
|
const type = member.groupId === member2.groupId ? "MATE" : "ENEMY";
|
|
const won =
|
|
winner === "ALPHA"
|
|
? member.groupId === match.alphaGroupId
|
|
: member.groupId === match.bravoGroupId;
|
|
|
|
addMapResult({
|
|
ownerUserId: member.id,
|
|
otherUserId: member2.id,
|
|
type,
|
|
outcome: won ? "win" : "loss",
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
const winner = winnersArrayToWinner(winners);
|
|
|
|
for (const member of members) {
|
|
for (const member2 of members) {
|
|
if (member.id === member2.id) continue;
|
|
|
|
const type = member.groupId === member2.groupId ? "MATE" : "ENEMY";
|
|
const won =
|
|
winner === "ALPHA"
|
|
? member.groupId === match.alphaGroupId
|
|
: member.groupId === match.bravoGroupId;
|
|
|
|
result.push({
|
|
ownerUserId: member.id,
|
|
otherUserId: member2.id,
|
|
type,
|
|
mapWins: 0,
|
|
mapLosses: 0,
|
|
season,
|
|
setWins: won ? 1 : 0,
|
|
setLosses: won ? 0 : 1,
|
|
});
|
|
}
|
|
}
|
|
|
|
return result;
|
|
}
|