(() => { "use strict"; const SERVER_INFO = { us: "108.175.11.140", eu: "65.21.79.231", }; const GUIDE_TREE = { connection: { label: "Connection Guide", children: { overview: { label: "Overview", doc: "docs/guide/connection/overview.md", }, dreamcast: { label: "Dreamcast", children: { hardware: { label: "Hardware", doc: "docs/guide/connection/dreamcast/hardware.md", }, flycastDialup: { label: "Flycast (Dialup)", doc: "docs/guide/connection/dreamcast/flycast-dialup.md", }, flycastBba: { label: "Flycast (BBA)", doc: "docs/guide/connection/dreamcast/flycast-bba.md", }, }, }, pc: { label: "PC", children: { pc: { label: "PC", children: { windows: { label: "Windows", doc: "docs/guide/connection/pc/pc-windows.md", }, linux: { label: "Linux", doc: "docs/guide/connection/pc/pc-linux.md", }, }, }, blueBurst: { label: "Blue Burst", children: { windows: { label: "Windows", doc: "docs/guide/connection/pc/blue-burst-windows.md", }, linux: { label: "Linux", doc: "docs/guide/connection/pc/blue-burst-linux.md", }, }, }, }, }, gamecube: { label: "GameCube", children: { hardwareBba: { label: "Hardware (BBA)", doc: "docs/guide/connection/gamecube/hardware-bba.md", }, dolphin: { label: "Dolphin", doc: "docs/guide/connection/gamecube/dolphin.md", }, nintendont: { label: "Nintendont", doc: "docs/guide/connection/gamecube/nintendont.md", }, }, }, xbox: { label: "Xbox", doc: "docs/guide/connection/xbox.md", }, psp: { label: "Phantasy Star Portable", doc: "docs/guide/connection/phantasy-star-portable.md", }, serverSideSaves: { label: "Server-side saves", doc: "docs/guide/connection/server-side-saves.md", }, commonProblems: { label: "Common problems", doc: "docs/guide/connection/common-problems.md", }, quickReference: { label: "Quick reference", doc: "docs/guide/connection/quick-reference.md", }, }, }, peeps: { label: "Peeps Guide", children: { gettingStarted: { label: "Getting Started", doc: "docs/guide/peeps/getting-started.md", }, crossplayRooms: { label: "Crossplay Rooms", doc: "docs/guide/peeps/crossplay-rooms.md", }, xpPeriods: { label: "XP Periods", doc: "docs/guide/peeps/xp-periods.md", }, brutalPeeps: { label: "Brutal Peeps", doc: "docs/guide/peeps/brutal-peeps.md", }, }, }, hardcore: { label: "Hardcore Peeps Guide", children: { gettingStarted: { label: "Getting Started", doc: "docs/guide/hardcore/getting-started.md", }, progression: { label: "Progression", doc: "docs/guide/hardcore/progression.md", }, mesetaAndBankLimits: { label: "Meseta and Bank Limits", doc: "docs/guide/hardcore/meseta-and-bank-limits.md", }, pointsSystem: { label: "Points System", doc: "docs/guide/hardcore/points-system.md", }, brutalPeeps: { label: "Brutal Peeps", doc: "docs/guide/hardcore/brutal-peeps.md", }, }, }, }; const qs = (sel) => document.querySelector(sel); const selects = [ qs("#guide-level-0"), qs("#guide-level-1"), qs("#guide-level-2"), qs("#guide-level-3"), ]; const wrappers = [ null, qs("#guide-level-1-wrap"), qs("#guide-level-2-wrap"), qs("#guide-level-3-wrap"), ]; const labels = [ null, qs('label[for="guide-level-1"]'), qs('label[for="guide-level-2"]'), qs('label[for="guide-level-3"]'), ]; const box = qs("#guide-content"); let pendingPath = null; let loadingPath = ""; const mdCache = new Map(); function esc(value) { return String(value ?? "") .replaceAll("&", "&") .replaceAll("<", "<") .replaceAll(">", ">") .replaceAll('"', """) .replaceAll("'", "'"); } function nodeChildren(node) { return node && node.children ? Object.entries(node.children) : []; } function fillSelect(select, children, preferredValue) { if (!select) return ""; const entries = Object.entries(children || {}); const previous = preferredValue || select.value; select.innerHTML = ""; for (const [key, child] of entries) { const opt = document.createElement("option"); opt.value = key; opt.textContent = child.label; select.appendChild(opt); } if (entries.some(([key]) => key === previous)) { select.value = previous; } else if (entries.length) { select.value = entries[0][0]; } return select.value; } function setStatus(message, kind = "") { if (!box) return; box.innerHTML = `
${esc(code)}`);
return token;
});
let html = esc(text);
html = html.replace(/\[([^\]]+)\]\(([^)]+)\)/g, (_, label, href) => {
return `${label}`;
});
html = html
.replace(/\*\*([^*]+)\*\*/g, "$1")
.replace(/\*([^*]+)\*/g, "$1");
codeSpans.forEach((span, index) => {
html = html.replaceAll(`@@CODE${index}@@`, span);
});
return html;
}
function renderMarkdown(markdown) {
const lines = String(markdown || "").replace(/\r\n/g, "\n").split("\n");
const out = [];
let paragraph = [];
let list = [];
let orderedList = [];
let code = [];
let inFence = false;
const fence = String.fromCharCode(96, 96, 96);
function flushParagraph() {
if (!paragraph.length) return;
out.push(`${inlineMarkdown(paragraph.join(" "))}
`); paragraph = []; } function flushList() { if (!list.length) return; out.push(`${esc(code.join("\n"))}`);
code = [];
}
function flushTextBlocks() {
flushParagraph();
flushList();
flushOrderedList();
}
for (const line of lines) {
const trimmed = line.trim();
if (trimmed.startsWith(fence)) {
flushTextBlocks();
if (inFence) {
flushCode();
inFence = false;
} else {
inFence = true;
code = [];
}
continue;
}
if (inFence) {
code.push(line);
continue;
}
if (/^ {4,}/.test(line)) {
flushTextBlocks();
code.push(line.replace(/^ {4}/, ""));
continue;
}
if (code.length && trimmed === "") {
flushCode();
continue;
}
if (code.length) {
flushCode();
}
if (!trimmed) {
flushTextBlocks();
continue;
}
if (/^(-{3,}|\*{3,}|_{3,})$/.test(trimmed)) {
flushTextBlocks();
out.push("