OOKNET                             [ /  search the index  ]  
──────────────────────────────────────────────────────────────────────────────────────
══════════════════════════════════════════════════════════════════════════════════════
OOKNET   [ /  search  ]  
────────────────────────────────────────────────
════════════════════════════════════════════════
 
 
master @ 115 LINES
 
[ HISTORY ]  [ UP ]
 

// Per-dungeon timer thresholds for MoP Challenge Modes, in milliseconds.
// Gold = the achievement par-time. Platinum / Title (aka "Remarkable")
// are tighter community/in-game cutoffs.

export type TimeTier = "title" | "platinum" | "gold";

export interface DungeonThresholds {
  goldMs: number;
  platinumMs: number;
  titleMs: number;
}

export const DUNGEON_THRESHOLDS: Record<number, DungeonThresholds> = {
  2: { goldMs: 900000, platinumMs: 615000, titleMs: 510000 }, // Temple of the Jad
e Serpent (15:00 / 10:15 / 8:30)
  56: { goldMs: 720000, platinumMs: 495000, titleMs: 390000 }, // Stormstout Brewe
ry        (12:00 / 8:15 / 6:30)
  57: { goldMs: 780000, platinumMs: 480000, titleMs: 330000 }, // Gate of the Sett
ing Sun   (13:00 / 8:00 / 5:30)
  58: { goldMs: 1260000, platinumMs: 840000, titleMs: 630000 }, // Shado-Pan Monas
tery       (21:00 / 14:00 / 10:30)
  59: { goldMs: 1050000, platinumMs: 735000, titleMs: 615000 }, // Siege of Niuzao
 Temple    (17:30 / 12:15 / 10:15)
  60: { goldMs: 720000, platinumMs: 495000, titleMs: 405000 }, // Mogu'shan Palace
          (12:00 / 8:15 / 6:45)
  76: { goldMs: 1140000, platinumMs: 615000, titleMs: 435000 }, // Scholomance    
           (19:00 / 10:15 / 7:15)
  77: { goldMs: 780000, platinumMs: 480000, titleMs: 255000 }, // Scarlet Halls   
          (13:00 / 8:00 / 4:15)
  78: { goldMs: 780000, platinumMs: 540000, titleMs: 330000 }, // Scarlet Monaster
y         (13:00 / 9:00 / 5:30)
};

// Slug ? dungeon_id, for callsites that have the URL slug but not the numeric id.
// Slugs match those produced by the Go generator.
export const DUNGEON_SLUG_TO_ID: Record<string, number> = {
  "temple-of-the-jade-serpent": 2,
  "stormstout-brewery": 56,
  "gate-of-the-setting-sun": 57,
  "shado-pan-monastery": 58,
  "siege-of-niuzao-temple": 59,
  "mogu-shan-palace": 60,
  scholomance: 76,
  "scarlet-halls": 77,
  "scarlet-monastery": 78,
};

export function dungeonIdFromSlug(
  slug: string | undefined | null,
): number | null {
  if (!slug) return null;
  return DUNGEON_SLUG_TO_ID[slug] ?? null;
}

/**
 * In-game cutoffs are lenient: the displayed cutoff is the first second that
 * still earns the medal. e.g. a 5:30.800 run beats a "5:30" title cutoff,
 * because the timer reads "5:30" until it ticks over to 5:31. So the actual
 * pass condition is `duration < threshold + 1000ms`.
 */
const LENIENCY_MS = 1000;

/**
 * Returns the highest tier the run beat, or null if it didn't beat gold (or
 * the dungeon is unknown).
 */
export function getTimeTier(
  dungeonId: number,
  durationMs: number,
): TimeTier | null {
  const t = DUNGEON_THRESHOLDS[dungeonId];
  if (!t) return null;
  if (durationMs < t.titleMs + LENIENCY_MS) return "title";
  if (durationMs < t.platinumMs + LENIENCY_MS) return "platinum";
  if (durationMs < t.goldMs + LENIENCY_MS) return "gold";
  return null;
}

/**
 * CSS class slug for the tier the run hit, e.g. "time--title".
 * Use this for client-rendered widgets that build DOM in JS.
 * Returns null when the run didn't beat gold or the dungeon is unknown.
 */
export function getTimeClass(
  dungeonId: number,
  durationMs: number,
): string | null {
  const tier = getTimeTier(dungeonId, durationMs);
  return tier ? `time--${tier}` : null;
}

const TIER_LABEL: Record<TimeTier, string> = {
  title: "Title",
  platinum: "Platinum",
  gold: "Gold",
};

// hover text like "Title - cutoff 8:30"; null when no tier was hit.
// "cutoff" not "under" because the in-game check is lenient (8:30.999
// still earns title when the cutoff is 8:30).
export function getTierTooltip(
  dungeonId: number,
  durationMs: number,
): string | null {
  const tier = getTimeTier(dungeonId, durationMs);
  if (!tier) return null;
  const t = DUNGEON_THRESHOLDS[dungeonId];
  if (!t) return null;
  const cutoffMs =
    tier === "title"
      ? t.titleMs
      : tier === "platinum"
        ? t.platinumMs
        : t.goldMs;
  return `${TIER_LABEL[tier]} - cutoff ${formatCutoff(cutoffMs)}`;
}

function formatCutoff(ms: number): string {
  const totalSec = Math.floor(ms / 1000);
  const m = Math.floor(totalSec / 60);
  const s = totalSec % 60;
  return `${m}:${s.toString().padStart(2, "0")}`;
}

// Per-dungeon timer thresholds for MoP Chal
lenge Modes, in milliseconds.
// Gold = the achievement par-time. Platinum
 / Title (aka "Remarkable")
// are tighter community/in-game cutoffs.

export type TimeTier = "title" | "platinum" 
| "gold";

export interface DungeonThresholds {
  goldMs: number;
  platinumMs: number;
  titleMs: number;
}

export const DUNGEON_THRESHOLDS: Record<numb
er, DungeonThresholds> = {
  2: { goldMs: 900000, platinumMs: 615000, t
itleMs: 510000 }, // Temple of the Jade Serp
ent (15:00 / 10:15 / 8:30)
  56: { goldMs: 720000, platinumMs: 495000, 
titleMs: 390000 }, // Stormstout Brewery    
    (12:00 / 8:15 / 6:30)
  57: { goldMs: 780000, platinumMs: 480000, 
titleMs: 330000 }, // Gate of the Setting Su
n   (13:00 / 8:00 / 5:30)
  58: { goldMs: 1260000, platinumMs: 840000,
 titleMs: 630000 }, // Shado-Pan Monastery  
     (21:00 / 14:00 / 10:30)
  59: { goldMs: 1050000, platinumMs: 735000,
 titleMs: 615000 }, // Siege of Niuzao Templ
e    (17:30 / 12:15 / 10:15)
  60: { goldMs: 720000, platinumMs: 495000, 
titleMs: 405000 }, // Mogu'shan Palace      
    (12:00 / 8:15 / 6:45)
  76: { goldMs: 1140000, platinumMs: 615000,
 titleMs: 435000 }, // Scholomance          
     (19:00 / 10:15 / 7:15)
  77: { goldMs: 780000, platinumMs: 480000, 
titleMs: 255000 }, // Scarlet Halls         
    (13:00 / 8:00 / 4:15)
  78: { goldMs: 780000, platinumMs: 540000, 
titleMs: 330000 }, // Scarlet Monastery     
    (13:00 / 9:00 / 5:30)
};

// Slug ? dungeon_id, for callsites that hav
e the URL slug but not the numeric id.
// Slugs match those produced by the Go gene
rator.
export const DUNGEON_SLUG_TO_ID: Record<stri
ng, number> = {
  "temple-of-the-jade-serpent": 2,
  "stormstout-brewery": 56,
  "gate-of-the-setting-sun": 57,
  "shado-pan-monastery": 58,
  "siege-of-niuzao-temple": 59,
  "mogu-shan-palace": 60,
  scholomance: 76,
  "scarlet-halls": 77,
  "scarlet-monastery": 78,
};

export function dungeonIdFromSlug(
  slug: string | undefined | null,
): number | null {
  if (!slug) return null;
  return DUNGEON_SLUG_TO_ID[slug] ?? null;
}

/**
 * In-game cutoffs are lenient: the displaye
d cutoff is the first second that
 * still earns the medal. e.g. a 5:30.800 ru
n beats a "5:30" title cutoff,
 * because the timer reads "5:30" until it t
icks over to 5:31. So the actual
 * pass condition is `duration < threshold +
 1000ms`.
 */
const LENIENCY_MS = 1000;

/**
 * Returns the highest tier the run beat, or
 null if it didn't beat gold (or
 * the dungeon is unknown).
 */
export function getTimeTier(
  dungeonId: number,
  durationMs: number,
): TimeTier | null {
  const t = DUNGEON_THRESHOLDS[dungeonId];
  if (!t) return null;
  if (durationMs < t.titleMs + LENIENCY_MS) 
return "title";
  if (durationMs < t.platinumMs + LENIENCY_M
S) return "platinum";
  if (durationMs < t.goldMs + LENIENCY_MS) r
eturn "gold";
  return null;
}

/**
 * CSS class slug for the tier the run hit, 
e.g. "time--title".
 * Use this for client-rendered widgets that
 build DOM in JS.
 * Returns null when the run didn't beat gol
d or the dungeon is unknown.
 */
export function getTimeClass(
  dungeonId: number,
  durationMs: number,
): string | null {
  const tier = getTimeTier(dungeonId, durati
onMs);
  return tier ? `time--${tier}` : null;
}

const TIER_LABEL: Record<TimeTier, string> =
 {
  title: "Title",
  platinum: "Platinum",
  gold: "Gold",
};

// hover text like "Title - cutoff 8:30"; nu
ll when no tier was hit.
// "cutoff" not "under" because the in-game 
check is lenient (8:30.999
// still earns title when the cutoff is 8:30
).
export function getTierTooltip(
  dungeonId: number,
  durationMs: number,
): string | null {
  const tier = getTimeTier(dungeonId, durati
onMs);
  if (!tier) return null;
  const t = DUNGEON_THRESHOLDS[dungeonId];
  if (!t) return null;
  const cutoffMs =
    tier === "title"
      ? t.titleMs
      : tier === "platinum"
        ? t.platinumMs
        : t.goldMs;
  return `${TIER_LABEL[tier]} - cutoff ${for
matCutoff(cutoffMs)}`;
}

function formatCutoff(ms: number): string {
  const totalSec = Math.floor(ms / 1000);
  const m = Math.floor(totalSec / 60);
  const s = totalSec % 60;
  return `${m}:${s.toString().padStart(2, "0
")}`;
}
 
──────────────────────────────────────────────────────────────────────────────────────
OOKNET
────────────────────────────────────────────────
OOKNET