added portals, quest tracking, discord monitor etc etc

This commit is contained in:
erik 2025-06-23 19:26:44 +00:00
parent 72de9b0f7f
commit dffd295091
312 changed files with 4130 additions and 7 deletions

View file

@ -189,6 +189,11 @@ let heatTimeout = null;
const HEAT_PADDING = 50; // px beyond viewport to still draw
const HEAT_THROTTLE = 16; // ~60 fps
/* ---------- Portal Map Globals ---------- */
let portalEnabled = false;
let portalData = null;
let portalContainer = null;
/**
* ---------- Player Color Assignment ----------------------------
* Uses a predefined accessible color palette for player dots to ensure
@ -446,6 +451,107 @@ function clearHeatmap() {
}
}
/* ---------- Portal Map Functions ---------- */
function initPortalMap() {
portalContainer = document.getElementById('portals');
if (!portalContainer) {
console.error('Portal container not found');
return;
}
const toggle = document.getElementById('portalToggle');
if (toggle) {
toggle.addEventListener('change', e => {
portalEnabled = e.target.checked;
if (portalEnabled) {
fetchPortalData();
} else {
clearPortals();
}
});
}
}
async function fetchPortalData() {
try {
const response = await fetch(`${API_BASE}/portals`);
if (!response.ok) {
throw new Error(`Portal API error: ${response.status}`);
}
const data = await response.json();
portalData = data.portals; // [{character_name, portal_name, ns, ew, z}]
console.log(`Loaded ${portalData.length} portal discoveries from last 24 hours`);
renderPortals();
} catch (err) {
console.error('Failed to fetch portal data:', err);
}
}
function parseCoordinate(coord) {
// Handle both formats:
// String format: "42.3N", "15.7S", "33.7E", "28.2W"
// Numeric format: "-96.9330958" (already signed)
// Check if it's already a number
if (typeof coord === 'number') {
return coord;
}
// Check if it's a numeric string
const numericValue = parseFloat(coord);
if (!isNaN(numericValue) && coord.match(/^-?\d+\.?\d*$/)) {
return numericValue;
}
// Parse string format like "42.3N"
const match = coord.match(/^([0-9.]+)([NSEW])$/);
if (!match) return 0;
const value = parseFloat(match[1]);
const direction = match[2];
if (direction === 'S' || direction === 'W') {
return -value;
}
return value;
}
function renderPortals() {
if (!portalEnabled || !portalData || !portalContainer || !imgW || !imgH) {
return;
}
// Clear existing portals
clearPortals();
for (const portal of portalData) {
// Coordinates are already floats from the API
const ns = portal.ns;
const ew = portal.ew;
// Convert to pixel coordinates
const { x, y } = worldToPx(ew, ns);
// Create portal icon
const icon = document.createElement('div');
icon.className = 'portal-icon';
icon.style.left = `${x}px`;
icon.style.top = `${y}px`;
icon.title = `${portal.portal_name} (discovered by ${portal.character_name})`;
portalContainer.appendChild(icon);
}
console.log(`Rendered ${portalData.length} portal icons`);
}
function clearPortals() {
if (portalContainer) {
portalContainer.innerHTML = '';
}
}
function debounce(fn, ms) {
let timeout;
return (...args) => {
@ -1163,6 +1269,7 @@ img.onload = () => {
startPolling();
initWebSocket();
initHeatMap();
initPortalMap();
};
// Ensure server health polling starts regardless of image loading
@ -1874,4 +1981,12 @@ function openPlayerDebug() {
window.open('/debug.html', '_blank');
}
/**
* Opens the Quest Status interface in a new browser tab.
*/
function openQuestStatus() {
// Open the Quest Status page in a new tab
window.open('/quest-status.html', '_blank');
}