86 lines
No EOL
3.3 KiB
TypeScript
86 lines
No EOL
3.3 KiB
TypeScript
import { Config } from "@systems/config";
|
|
import { submitScore, detectSlot, normalizeSlot } from "@systems/scores";
|
|
import { getEffectiveCharacter } from "@systems/borrow";
|
|
import { format } from "@format";
|
|
import { getEmoji } from "@systems/emojis";
|
|
|
|
// ─── Types ────────────────────────────────────────────────────────────────────
|
|
|
|
export interface ScoreSubmitInput {
|
|
userKey: string;
|
|
pts: number;
|
|
slot?: number | string | null; // number = already resolved, string = needs normalizing, null/undefined = auto-detect
|
|
k?: number;
|
|
d?: number;
|
|
atk?: number;
|
|
def?: number;
|
|
heal?: number;
|
|
submittedByOfficer?: boolean;
|
|
}
|
|
|
|
export type ScoreSubmitResult =
|
|
| { ok: true; message: string }
|
|
| { ok: false; message: string };
|
|
|
|
// ─── Core ─────────────────────────────────────────────────────────────────────
|
|
|
|
export namespace score {
|
|
/**
|
|
* Resolve, validate and persist a score submission for a given userKey.
|
|
* Used by both the slash command handler and the modal submit handler.
|
|
*/
|
|
export async function submitForUser(input: ScoreSubmitInput): Promise<ScoreSubmitResult> {
|
|
const { userKey, pts, k, d, atk, def, heal, submittedByOfficer = false } = input;
|
|
|
|
const { char, borrowedFrom } = getEffectiveCharacter(userKey);
|
|
if (!char) {
|
|
return { ok: false, message: "❌ No active character found. Use `/tg char set-active` first." };
|
|
}
|
|
|
|
// Resolve slot
|
|
let slot: number | null = null;
|
|
if (typeof input.slot === "number") {
|
|
slot = input.slot;
|
|
} else if (typeof input.slot === "string") {
|
|
slot = normalizeSlot(input.slot);
|
|
if (slot === null) {
|
|
return { ok: false, message: `❌ Could not parse slot "${input.slot}".` };
|
|
}
|
|
} else {
|
|
slot = detectSlot() ?? Config.get({ section: "poll", key: "slots" }).find((s) => s.active)?.tgHour ?? 20;
|
|
}
|
|
|
|
await submitScore({
|
|
userKey: borrowedFrom ?? userKey,
|
|
playedBy: borrowedFrom ? userKey : undefined,
|
|
characterName: char.name,
|
|
cls: char.class,
|
|
nation: char.nation,
|
|
pts,
|
|
k,
|
|
d,
|
|
slot,
|
|
atk,
|
|
def,
|
|
heal,
|
|
submittedByOfficer,
|
|
});
|
|
|
|
const scoreEmoji = getEmoji("score") || "📊";
|
|
const kdEmoji = getEmoji("kd") || "⚔️";
|
|
const borrowNote = borrowedFrom ? ` *(borrowed from ${borrowedFrom})*` : "";
|
|
const kdNote = k !== undefined && d !== undefined ? `\n${kdEmoji} ${k}/${d}` : "";
|
|
const statsNote = [
|
|
atk !== undefined ? `ATK: ${atk}` : null,
|
|
def !== undefined ? `DEF: ${def}` : null,
|
|
heal !== undefined ? `HEAL: ${heal}` : null,
|
|
].filter(Boolean).join(" · ");
|
|
|
|
const charDisplay = format.char(char);
|
|
return {
|
|
ok: true,
|
|
message: `✅ ${scoreEmoji} **${pts}** submitted for ${charDisplay}${borrowNote} (${slot}:00 TG)${kdNote}${statsNote ? `\n${statsNote}` : ""}`,
|
|
// message: `✅ ${scoreEmoji} **${pts}** submitted for ${charDisplay}${borrowNote} (${slot}:00 TG)${kdNote}${statsNote ? `\n${statsNote}` : ""}`,
|
|
};
|
|
}
|
|
} |