Release Healer Man 0.1.39
This commit is contained in:
1 parent
b417b7c3c3
commit
ed0d2fea3d
51 files changed
+17811
-49
No files matched your search
@@ -0,0 +1,78 @@
|
||||
export interface DungeonRunMember {
|
||||
readonly name: string;
|
||||
readonly classId: string;
|
||||
readonly level: number;
|
||||
readonly secondaryClassId?: string;
|
||||
readonly role: string;
|
||||
readonly npc: boolean;
|
||||
}
|
||||
|
||||
export interface DungeonRunProgress {
|
||||
readonly id: string;
|
||||
readonly dungeonId: string;
|
||||
readonly difficultyId: string;
|
||||
readonly startedAt: number | null;
|
||||
readonly finishedAt: number | null;
|
||||
readonly durationMs: number | null;
|
||||
readonly timed: boolean;
|
||||
readonly killedBossIds: readonly string[];
|
||||
readonly party: readonly DungeonRunMember[];
|
||||
}
|
||||
|
||||
export interface DungeonRunRecord {
|
||||
readonly id: string;
|
||||
readonly dungeonId: string;
|
||||
readonly difficultyId: string;
|
||||
readonly durationMs: number;
|
||||
readonly finishedAt: number;
|
||||
readonly killedBossIds: readonly string[];
|
||||
readonly party: readonly DungeonRunMember[];
|
||||
readonly fullClear: boolean;
|
||||
}
|
||||
|
||||
export type DungeonClearFilter = "full" | "final";
|
||||
export interface RankedDungeonRun extends DungeonRunRecord { readonly rank: number }
|
||||
export interface DungeonLeaderboard {
|
||||
readonly entries: readonly RankedDungeonRun[];
|
||||
readonly total: number;
|
||||
}
|
||||
export interface DungeonRunPlacement {
|
||||
readonly finalRank: number;
|
||||
readonly finalTotal: number;
|
||||
readonly fullRank: number | null;
|
||||
readonly fullTotal: number;
|
||||
}
|
||||
|
||||
export function formatDungeonDuration(durationMs: number): string {
|
||||
const tenths = Math.floor(Math.max(0, durationMs) / 100);
|
||||
const seconds = Math.floor(tenths / 10);
|
||||
const minutes = Math.floor(seconds / 60);
|
||||
return `${String(minutes).padStart(2, "0")}:${String(seconds % 60).padStart(2, "0")}.${tenths % 10}`;
|
||||
}
|
||||
|
||||
/** Untrusted checkpoint/local-storage data must never reset or invent a ranked timer. */
|
||||
export function normalizeDungeonRunProgress(value: unknown): DungeonRunProgress | null {
|
||||
if (!value || typeof value !== "object") return null;
|
||||
const input = value as DungeonRunProgress;
|
||||
const text = (entry: unknown) => typeof entry === "string" && entry.length > 0 && entry.length <= 100;
|
||||
const time = (entry: unknown) => entry === null || (typeof entry === "number" && Number.isFinite(entry) && entry >= 0);
|
||||
if (!text(input.id) || !text(input.dungeonId) || !text(input.difficultyId)
|
||||
|| !time(input.startedAt) || !time(input.finishedAt) || !time(input.durationMs)
|
||||
|| typeof input.timed !== "boolean" || !Array.isArray(input.killedBossIds)
|
||||
|| input.killedBossIds.length > 100 || !input.killedBossIds.every(text)
|
||||
|| !Array.isArray(input.party) || input.party.length > 5
|
||||
|| !input.party.every((member) => member && text(member.name) && text(member.classId)
|
||||
&& Number.isInteger(member.level) && member.level >= 1 && member.level <= 80
|
||||
&& ["tank", "healer", "damage"].includes(member.role) && typeof member.npc === "boolean"
|
||||
&& (member.secondaryClassId === undefined || text(member.secondaryClassId)))
|
||||
|| (input.finishedAt !== null && (input.startedAt === null || input.finishedAt < input.startedAt))
|
||||
|| (input.durationMs !== null && (input.finishedAt === null || input.durationMs < 1))
|
||||
|| (input.finishedAt !== null && (input.durationMs === null || input.party.length === 0
|
||||
|| input.durationMs !== Math.max(1, Math.round(input.finishedAt - input.startedAt!))))) return null;
|
||||
return { id: input.id, dungeonId: input.dungeonId, difficultyId: input.difficultyId,
|
||||
startedAt: input.startedAt, finishedAt: input.finishedAt, durationMs: input.durationMs,
|
||||
timed: input.timed, killedBossIds: [...new Set(input.killedBossIds)],
|
||||
party: input.party.map((member) => ({ name: member.name, classId: member.classId,
|
||||
level: member.level, role: member.role, npc: member.npc,
|
||||
...(member.secondaryClassId ? { secondaryClassId: member.secondaryClassId } : {}) })) };
|
||||
}
|
||||
Reference in new issue
Block a user