tunic-tracker-redux/tunictracker/tracker/static/tracker/assets/main.js

1009 lines
32 KiB
JavaScript

import translate from "./translate-hints.js";
import update from "./fetch-updates.js";
// Global state for overview
var current_scene = "";
var current_seed = Number.MAX_VALUE;
var current_checks = 0;
var current_entrances = 0;
var current_codes = Number.MAX_VALUE;
var current_hints = 0;
// Global state internal
var server_address = "localhost:51111/";
var can_access_api_server = true;
var is_timeout = false;
var hide_completed_areas = false;
var cross_codes = {};
var total_checks = 0;
var total_entrances = 0;
var all_scenes = [];
var image_translations = {};
window.onload = async () => {
await get_updated_server_address();
await parse_cross_codes();
await parse_image_translations();
await initialize_elements();
await refresh_elements();
};
async function parse_cross_codes() {
fetch(`${document.URL}static/tracker/data/holy_cross_codes.json`)
.then((response) => response.json())
.then(
(data) => {
cross_codes = JSON.parse(JSON.stringify(data));
},
(error) => {
console.error(error);
}
);
}
async function parse_image_translations() {
fetch(`${document.URL}static/tracker/data/image_translations.json`)
.then((response) => response.json())
.then(
(data) => {
image_translations = JSON.parse(JSON.stringify(data));
},
(error) => {
console.error(error);
}
);
}
async function get_updated_server_address() {
fetch(`${document.URL}get/address`)
.then(
(response) => response.json(),
(error) => {
console.error(error);
}
)
.then(
(data) => {
const parsed_data = JSON.parse(JSON.stringify(data));
server_address = parsed_data["listen_address"];
},
(error) => {
console.error(error);
}
);
}
// A function to call when the page loads to ensure that we have the correct data when we connect to the server.
async function initialize_elements() {
// Grab all updates from the backend.
let overview = await update.refresh_overview(server_address);
if (!overview.overview) {
return;
}
const checks = await update.refresh_checks(server_address);
const entrances = await update.refresh_entrances(server_address);
const hints = await update.refresh_hints(server_address);
overview = overview.overview;
// Initialize global state
current_checks = checks.collected;
current_entrances = entrances.found;
total_checks = checks.total;
total_entrances = entrances.total;
all_scenes = Array.from(Object.keys(checks.scenes));
await update_overview(overview, false);
// Initialize breakdown list
let breakdown_list = document
.getElementById("breakdown-list")
.cloneNode(true);
let summary_list = document.getElementById("summary-list").cloneNode(true);
// Initialize the breakdown and summary lists
breakdown_list = await initialize_breakdown_list(
breakdown_list,
checks,
entrances
);
summary_list = await initialize_summary_list(summary_list, checks, entrances);
// Replace breakdown list
document
.getElementById("breakdown-list")
.replaceWith(breakdown_list.cloneNode(true));
// Replace summary list
document
.getElementById("summary-list")
.replaceWith(summary_list.cloneNode(true));
// Update codes list
update_codes(overview.codes);
// Update hints list
update_hints(hints);
return;
}
async function refresh_elements() {
const response = await update.refresh_overview(server_address);
// Check if the "Hide completed areas" option is checked
hide_completed_areas = document.getElementById("hideDone").checked;
if (response.overview) {
if (!can_access_api_server) {
console.info("I found the server!");
document.getElementById("status-block").classList.add("hidden");
can_access_api_server = true;
await initialize_elements();
}
is_timeout = false;
await update_if_changes(response.overview);
} else if (response.error.error) {
if (!is_timeout) {
is_timeout = true;
console.debug("Received timeout from API server.");
}
if (!can_access_api_server) {
console.info("I found the server!");
document.getElementById("status-block").classList.add("hidden");
can_access_api_server = true;
}
} else {
if (can_access_api_server) {
console.debug("Could not access the API server.");
document.getElementById("status-block").classList.remove("hidden");
}
can_access_api_server = false;
}
setTimeout(refresh_elements, 500);
}
async function update_if_changes(overview) {
const changed_seed = overview.seed != current_seed;
const changed_scene = overview.scene != current_scene;
const changed_checks = overview.items != current_checks;
const changed_entrances = overview.entrances != current_entrances;
const changed_hints = overview.hints != current_hints;
const any_change =
changed_seed ||
changed_scene ||
changed_checks ||
changed_entrances ||
changed_hints;
if (any_change) {
await perform_updates(
changed_seed,
changed_checks,
changed_entrances,
changed_hints
);
await update_overview(overview, changed_scene);
}
await update_codes(overview.codes);
}
async function perform_updates(
changed_seed,
changed_checks,
changed_entrances,
changed_hints
) {
if (changed_seed) {
initialize_elements();
console.info(`Seed changed to: ${current_seed}`);
} else {
if (changed_checks) {
update.refresh_checks(server_address).then((data) => {
update_breakdown_list(data, { entrances: false, checks: true });
update_summary_list(data, { entrances: false, checks: true });
});
}
if (changed_entrances) {
update.refresh_entrances(server_address).then((data) => {
update_breakdown_list(data, { entrances: true, checks: false });
update_summary_list(data, { entrances: true, checks: false });
});
}
if (changed_hints) {
update.refresh_hints(server_address).then((data) => update_hints(data));
}
}
}
async function update_overview(overview, changed_scene) {
let overview_checks_title = document
.getElementById("overview-totals")
.querySelector(".overview-checks");
let overview_entrances_title = document
.getElementById("overview-totals")
.querySelector(".overview-entrances");
// Set content to updated data.
overview_checks_title.textContent = `${overview.items}/${total_checks} (${
total_checks - overview.items
} left)`;
overview_entrances_title.textContent = `${
overview.entrances * 2
}/${total_entrances} (${total_entrances - overview.entrances * 2} left)`;
// Set global state
current_seed = overview.seed;
current_scene = overview.scene;
current_checks = overview.items;
current_entrances = overview.entrances;
current_hints = overview.hints;
if (changed_scene && all_scenes.some((scene) => scene == overview.scene)) {
await update_scene(overview.scene);
}
}
async function update_codes(codes) {
// Codes that are always active
const default_cross_codes = cross_codes.Default;
let new_cross_codes_block_list = document
.getElementById("codes-list")
.cloneNode(true);
let cross_codes_block_list_item = document
.getElementById("codes-list")
.firstElementChild.cloneNode(true);
new_cross_codes_block_list.innerHTML = "";
new_cross_codes_block_list.appendChild(
cross_codes_block_list_item.cloneNode(true)
);
cross_codes_block_list_item.classList.remove("hidden");
const codes_length = Array.from(Object.keys(codes)).length;
if (current_codes != Array.from(Object.keys(codes)).length) {
Object.keys(codes)
.sort((i, j) => {
return codes[i].Distance - codes[j].Distance;
})
.forEach((codename, index) => {
cross_codes_block_list_item.querySelector(
".codes-list-item-title"
).textContent = codename;
if (codes[codename].Global) {
cross_codes_block_list_item.querySelector(
".codes-list-item-code"
).textContent = cross_codes["Global"][codename]
.replace(/U/g, "⬆️")
.replace(/R/g, "➡️")
.replace(/D/g, "⬇️")
.replace(/L/g, "⬅️");
} else {
cross_codes_block_list_item.querySelector(
".codes-list-item-code"
).textContent = cross_codes[current_scene][codename]
.replace(/U/g, "⬆️")
.replace(/R/g, "➡️")
.replace(/D/g, "⬇️")
.replace(/L/g, "⬅️");
}
cross_codes_block_list_item.dataset.codename = codename;
cross_codes_block_list_item.dataset.order = index;
new_cross_codes_block_list.appendChild(
cross_codes_block_list_item.cloneNode(true)
);
});
Object.keys(default_cross_codes).forEach((code) => {
cross_codes_block_list_item.querySelector(
".codes-list-item-title"
).textContent = code;
cross_codes_block_list_item.querySelector(
".codes-list-item-code"
).textContent = default_cross_codes[code]
.replace(/U/g, "⬆️")
.replace(/R/g, "➡️")
.replace(/D/g, "⬇️")
.replace(/L/g, "⬅️");
new_cross_codes_block_list.appendChild(
cross_codes_block_list_item.cloneNode(true)
);
});
document
.getElementById("codes-list")
.replaceWith(new_cross_codes_block_list);
// Change the number of current codes if it's different
current_codes = codes_length;
} else {
Object.keys(codes)
.sort((i, j) => {
return codes[i].Distance - codes[j].Distance;
})
.forEach((code, index) => {
const classes = Array.from(
document
.getElementById("codes-list")
.querySelector(`[data-codename="${code}"]`).classList
).filter((classname) => classname.startsWith("order-"));
if (classes.length > 0) {
document
.getElementById("codes-list")
.querySelector(`[data-codename="${code}"]`)
.classList.remove(classes);
}
if (codes[code].Global) {
document
.getElementById("codes-list")
.querySelector(`[data-codename="${code}"]`)
.classList.add(`order-last`);
} else {
document
.getElementById("codes-list")
.querySelector(`[data-codename="${code}"]`)
.classList.add(`order-${index + 1}`);
}
if (codes[code].InRange) {
document
.getElementById("codes-list")
.querySelector(`[data-codename="${code}"]`)
.classList.add(`bg-[#ffe28558]`);
} else {
document
.getElementById("codes-list")
.querySelector(`[data-codename="${code}"]`)
.classList.remove(`bg-[#ffe28558]`);
}
document
.getElementById("codes-list")
.querySelector(`[data-codename="${code}"]`).dataset.order = index + 1;
});
}
}
async function apply_summary_colors(summary) {
// Apply color coding to summary block
summary.element.classList.remove(
"from-highlight-both-light",
"from-highlight-checks-light",
"from-highlight-entrances-light",
"from-highlight-empty-light",
"from-highlight-undiscovered-light",
"to-highlight-both-dark",
"to-highlight-checks-dark",
"to-highlight-entrances-dark",
"to-highlight-empty-dark",
"to-highlight-undiscovered-dark",
"text-highlight-both-text",
"text-highlight-checks-text",
"text-highlight-entrances-text",
"text-highlight-empty-text",
"text-highlight-undiscovered-text"
);
if (summary.checks_total > 0 || summary.entrances_total > 0) {
if (
summary.checks_collected == summary.checks_total &&
summary.entrances_found == summary.entrances_total
) {
summary.element.classList.add(
"from-highlight-empty-light",
"to-highlight-empty-dark",
"text-highlight-empty-text"
);
} else if (
summary.checks_collected <= 0 &&
summary.entrances_found <= 0 &&
summary.entrances_total > 0
) {
summary.element.classList.add(
"from-highlight-undiscovered-light",
"to-highlight-undiscovered-dark",
"text-highlight-undiscovered-text"
);
} else if (summary.checks_collected >= summary.checks_total) {
summary.element.classList.add(
"from-highlight-checks-light",
"to-highlight-checks-dark",
"text-highlight-checks-text"
);
} else if (summary.entrances_found >= summary.entrances_total) {
summary.element.classList.add(
"from-highlight-entrances-light",
"to-highlight-entrances-dark",
"text-highlight-entrances-text"
);
} else {
summary.element.classList.add(
"from-highlight-both-light",
"to-highlight-both-dark",
"text-highlight-both-text"
);
}
} else {
summary.element.classList.add(
"from-highlight-undiscovered-light",
"to-highlight-undiscovered-dark",
"text-highlight-undiscovered-text"
);
}
return summary.element;
}
async function initialize_breakdown_list(breakdown_list, checks, entrances) {
// Initialize breakdown list
let breakdown_list_item = breakdown_list.firstElementChild.cloneNode(true);
breakdown_list.innerHTML = "";
breakdown_list.appendChild(breakdown_list_item.cloneNode(true));
breakdown_list_item.classList.remove("hidden");
for (const scene of Object.keys(checks.scenes)) {
// Initialize breakdown element
breakdown_list_item = await initialize_breakdown(
breakdown_list_item,
scene,
checks.scenes[scene],
entrances.scenes[scene]
);
// Add breakdown element to breakdown list
breakdown_list.appendChild(breakdown_list_item.cloneNode(true));
}
// Return initialized breakdown list
return breakdown_list;
}
async function initialize_breakdown(
breakdown_element,
scene,
checks,
entrances
) {
// Initialize breakdown data
breakdown_element.dataset.scene = scene;
breakdown_element.querySelector(".breakdown-block-title").textContent = scene;
// Populate breakdown lists
const breakdown_checks_list =
breakdown_element.querySelector(".breakdown-checks");
const breakdown_entrances_list = breakdown_element.querySelector(
".breakdown-entrances"
);
const breakdown_mapped_list = breakdown_element.querySelector(
".breakdown-block-mapped-list"
);
const new_breakdown_checks_list = await initialize_checks_list(
breakdown_checks_list,
checks
);
const new_entrances_lists = await initialize_entrances_list(
breakdown_entrances_list,
breakdown_mapped_list,
entrances
);
// Replace checks, entrances, and mapped lists
breakdown_element
.querySelector(".breakdown-checks")
.replaceWith(new_breakdown_checks_list);
breakdown_element
.querySelector(".breakdown-entrances")
.replaceWith(new_entrances_lists.entrances_list);
breakdown_element
.querySelector(".breakdown-block-mapped-list")
.replaceWith(new_entrances_lists.mapped_list);
// Hide breakdowns that aren't for the current scene
if (current_scene == scene) {
breakdown_element.classList.add("order-first");
breakdown_element.classList.remove("hidden", "order-last");
breakdown_element.dataset.current = true;
} else {
breakdown_element.classList.add("hidden", "order-last");
breakdown_element.classList.remove("order-first");
breakdown_element.dataset.current = false;
}
// Return initialized breakdown
return breakdown_element;
}
async function initialize_checks_list(checks_list, checks) {
// Initialize new checks list for the breakdown
let new_breakdown_block_checks_list = checks_list
.querySelector(".breakdown-block-checks-list")
.cloneNode(true);
let breakdown_block_checks_list_item =
new_breakdown_block_checks_list.firstElementChild.cloneNode(true);
// Clear new checks list and append blank entry
new_breakdown_block_checks_list.innerHTML = "";
new_breakdown_block_checks_list.appendChild(
breakdown_block_checks_list_item.cloneNode(true)
);
breakdown_block_checks_list_item.classList.remove("hidden");
// Update the check totals
checks_list.querySelector(
".breakdown-block-checks-title"
).textContent = `Checks: ${checks.collected}/${checks.total} (${checks.remaining} left)`;
checks_list.querySelector(
".breakdown-block-checks-title"
).dataset.checksCollected = checks.collected;
checks_list.querySelector(
".breakdown-block-checks-title"
).dataset.checksRemaining = checks.remaining;
checks_list.querySelector(
".breakdown-block-checks-title"
).dataset.checksTotal = checks.total;
// Populate new checks list
Object.keys(checks.checks).forEach((check) => {
if (checks.checks[check].name == "") {
breakdown_block_checks_list_item.classList.remove("hidden");
} else {
breakdown_block_checks_list_item.classList.add("hidden");
}
breakdown_block_checks_list_item.textContent = `${check}`;
breakdown_block_checks_list_item.dataset.check = check;
new_breakdown_block_checks_list.appendChild(
breakdown_block_checks_list_item.cloneNode(true)
);
});
// Replace checks list
checks_list
.querySelector(".breakdown-block-checks-list")
.replaceWith(new_breakdown_block_checks_list);
return checks_list;
}
async function initialize_entrances_list(
entrances_list,
mapped_list,
entrances
) {
// Create new entrances and mapped lists and append empty entrance and mapped element
let new_breakdown_block_entrances_list = entrances_list
.querySelector(".breakdown-block-entrances-list")
.cloneNode(true);
let breakdown_block_entrances_list_item =
new_breakdown_block_entrances_list.firstElementChild.cloneNode(true);
new_breakdown_block_entrances_list.innerHTML = "";
new_breakdown_block_entrances_list.appendChild(
breakdown_block_entrances_list_item.cloneNode(true)
);
breakdown_block_entrances_list_item.classList.remove("hidden");
let new_breakdown_block_mapped_list = mapped_list.cloneNode(true);
let breakdown_block_mapped_list_item =
new_breakdown_block_mapped_list.firstElementChild.cloneNode(true);
new_breakdown_block_mapped_list.innerHTML = "";
new_breakdown_block_mapped_list.appendChild(
breakdown_block_mapped_list_item.cloneNode(true)
);
breakdown_block_mapped_list_item.classList.remove("hidden");
// Update the entrance totals
entrances_list.querySelector(
".breakdown-block-entrances-title"
).textContent = `Entrances: ${entrances.found}/${entrances.total} (${entrances.remaining} left)`;
entrances_list.querySelector(
".breakdown-block-entrances-title"
).dataset.entrancesFound = entrances.found;
entrances_list.querySelector(
".breakdown-block-entrances-title"
).dataset.entrancesRemaining = entrances.remaining;
entrances_list.querySelector(
".breakdown-block-entrances-title"
).dataset.entrancesTotal = entrances.total;
// Populate new entrances and mapped lists
Object.keys(entrances.doors).forEach((entrance) => {
breakdown_block_entrances_list_item.dataset.entrance = entrance;
breakdown_block_entrances_list_item.textContent = `${entrance}`;
breakdown_block_mapped_list_item.dataset.mapped = entrance;
if (entrances.doors[entrance].door == "") {
breakdown_block_entrances_list_item.classList.remove("hidden");
new_breakdown_block_entrances_list.appendChild(
breakdown_block_entrances_list_item.cloneNode(true)
);
breakdown_block_mapped_list_item.textContent = `✔️ ${entrance} -> `;
breakdown_block_mapped_list_item.dataset.scene = "";
breakdown_block_mapped_list_item.classList.add("hidden");
new_breakdown_block_mapped_list.appendChild(
breakdown_block_mapped_list_item.cloneNode(true)
);
} else {
breakdown_block_entrances_list_item.classList.add("hidden");
new_breakdown_block_entrances_list.appendChild(
breakdown_block_entrances_list_item.cloneNode(true)
);
breakdown_block_mapped_list_item.textContent = `✔️ ${entrance} -> ${entrances.doors[entrance].door}`;
breakdown_block_mapped_list_item.dataset.scene =
entrances.doors[entrance].scene;
breakdown_block_mapped_list_item.classList.remove("hidden");
new_breakdown_block_mapped_list.appendChild(
breakdown_block_mapped_list_item.cloneNode(true)
);
}
});
entrances_list
.querySelector(".breakdown-block-entrances-list")
.replaceWith(new_breakdown_block_entrances_list);
// Return entrance and mapped list elements
return {
entrances_list: entrances_list,
mapped_list: new_breakdown_block_mapped_list,
};
}
async function initialize_summary_list(summary_list, checks, entrances) {
// Initialize summary list
let summary_list_item =
summary_list.firstElementChild.firstElementChild.cloneNode(true);
summary_list.firstElementChild.innerHTML = "";
summary_list.firstElementChild.appendChild(summary_list_item.cloneNode(true));
summary_list_item.classList.remove("hidden");
for (const scene of Object.keys(checks.scenes)) {
// Initialize summary element
summary_list_item = await initialize_summary(
summary_list_item,
scene,
checks.scenes[scene],
entrances.scenes[scene]
);
// Add summary element to summary list
summary_list.firstElementChild.appendChild(
summary_list_item.cloneNode(true)
);
}
// Return initialized summary list
return summary_list;
}
async function initialize_summary(summary_element, scene, checks, entrances) {
// Initialize summary data
summary_element.dataset.scene = scene;
summary_element.querySelector(".summary-title").textContent = scene;
const summary_checks = summary_element.querySelector(".summary-checks");
summary_checks.dataset.checksCollected = checks.collected;
summary_checks.dataset.checksRemaining = checks.remaining;
summary_checks.dataset.checksTotal = checks.total;
summary_checks.textContent = `Checks: ${checks.collected}/${checks.total} (${checks.remaining})`;
const summary_entrances = summary_element.querySelector(".summary-entrances");
summary_entrances.dataset.entrancesFound = entrances.found;
summary_entrances.dataset.entrancesRemaining = entrances.remaining;
summary_entrances.dataset.entrancesTotal = entrances.total;
summary_entrances.textContent = `Entrances: ${entrances.found}/${entrances.total} (${entrances.remaining})`;
// Apply summary color coding
summary_element.firstElementChild.replaceWith(
await apply_summary_colors({
element: summary_element.firstElementChild,
checks_collected: checks.collected,
checks_total: checks.total,
entrances_found: entrances.found,
entrances_total: entrances.total,
})
);
// Hide summaries for scenes with no entrances and the current scene and completed areas if "Hide completed areas" is checked
if (entrances.total <= 0 || current_scene == scene) {
summary_element.dataset.current = current_scene == scene;
summary_element.classList.add("hidden");
} else {
if (hide_completed_areas) {
if (checks.remaining > 0 && entrances.remaining > 0) {
summary_element.classList.remove("hidden");
} else {
summary_element.classList.add("hidden");
}
} else {
summary_element.dataset.current = false;
summary_element.classList.remove("hidden");
}
}
// Return initialized summary
return summary_element;
}
async function update_summary(scene, checks, entrances) {
// Grab summary checks and entrances
const summary_checks = document.querySelector(
`.summary[data-scene="${scene}"] .summary-checks`
);
const summary_entrances = document.querySelector(
`.summary[data-scene="${scene}"] .summary-entrances`
);
// Make variables for whether checks or entrances updated
const checks_changed =
summary_checks.dataset.checksCollected != checks.collected;
const entrances_changed =
summary_entrances.dataset.entrancesFound != entrances.found;
// Check for changes, and if so, update
if (checks_changed) {
summary_checks.dataset.checksCollected = checks.collected;
summary_checks.dataset.checksRemaining = checks.remaining;
summary_checks.dataset.checksTotal = checks.total;
summary_checks.textContent = `Checks: ${checks.collected}/${checks.total} (${checks.remaining})`;
}
if (entrances_changed) {
summary_entrances.dataset.entrancesFound = entrances.found;
summary_entrances.dataset.entrancesRemaining = entrances.remaining;
summary_entrances.dataset.entrancesTotal = entrances.total;
summary_entrances.textContent = `Entrances: ${entrances.found}/${entrances.total} (${entrances.remaining})`;
}
// Apply color coding
if (checks_changed || entrances_changed) {
document
.querySelector(`.summary[data-scene="${scene}"]`)
.firstElementChild.replaceWith(
await apply_summary_colors({
element: document.querySelector(`.summary[data-scene="${scene}"]`)
.firstElementChild,
checks_collected: checks.collected,
checks_total: checks.total,
entrances_found: entrances.found,
entrances_total: entrances.total,
})
);
}
}
async function update_summary_list(data, changed) {
// Check whether entrances or checks changed
if (changed.checks) {
Object.keys(data.scenes).forEach((scene) =>
update_summary(scene, data.scenes[scene], {
found: document.querySelector(
`.summary[data-scene="${scene}"] .summary-entrances`
).dataset.entrancesFound,
remaining: document.querySelector(
`.summary[data-scene="${scene}"] .summary-entrances`
).dataset.entrancesRemaining,
total: document.querySelector(
`.summary[data-scene="${scene}"] .summary-entrances`
).dataset.entrancesTotal,
})
);
} else if (changed.entrances) {
Object.keys(data.scenes).forEach((scene) =>
update_summary(
scene,
{
collected: document.querySelector(
`.summary[data-scene="${scene}"] .summary-checks`
).dataset.checksCollected,
remaining: document.querySelector(
`.summary[data-scene="${scene}"] .summary-checks`
).dataset.checksRemaining,
total: document.querySelector(
`.summary[data-scene="${scene}"] .summary-checks`
).dataset.checksTotal,
},
data.scenes[scene]
)
);
}
}
async function update_breakdown_checks(scene, checks) {
// Update the check totals
document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-checks-title`
).textContent = `Checks: ${checks.collected}/${checks.total} (${checks.remaining} left)`;
document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-checks-title`
).dataset.checksCollected = checks.collected;
document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-checks-title`
).dataset.checksRemaining = checks.remaining;
document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-checks-title`
).dataset.checksTotal = checks.total;
// Hide collected checks
for (const check of Object.keys(checks.checks)) {
const check_item = document.querySelector(
`.breakdown[data-scene="${scene}"] [data-check="${check}"]`
);
if (checks.checks[check].name == "") {
check_item.classList.remove("hidden");
} else {
check_item.classList.add("hidden");
}
}
}
async function update_breakdown_entrances(scene, entrances) {
// Update the entrance totals
document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-entrances-title`
).textContent = `Entrances: ${entrances.found}/${entrances.total} (${entrances.remaining} left)`;
document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-entrances-title`
).dataset.entrancesFound = entrances.found;
document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-entrances-title`
).dataset.entrancesRemaining = entrances.remaining;
document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-entrances-title`
).dataset.entrancesTotal = entrances.total;
// Map found entrances
for (const entrance of Object.keys(entrances.doors)) {
const entrance_item = document.querySelector(
`.breakdown[data-scene="${scene}"] [data-entrance="${entrance}"]`
);
const mapped_item = document.querySelector(
`.breakdown[data-scene="${scene}"] [data-mapped="${entrance}"]`
);
if (entrances.doors[entrance].door == "") {
entrance_item.classList.remove("hidden");
mapped_item.classList.add("hidden");
} else {
entrance_item.classList.add("hidden");
mapped_item.classList.remove("hidden");
mapped_item.dataset.scene = entrances.doors[entrance].scene;
mapped_item.textContent = `✔️ ${entrance} -> ${entrances.doors[entrance].door}`;
}
}
}
async function update_breakdown(scene, checks, entrances) {
// Grab breakdown checks and entrances
const breakdown_checks = document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-checks-title`
);
const breakdown_entrances = document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-entrances-title`
);
// Check for changes, and if so, update
if (breakdown_checks.dataset.checksCollected != checks.collected) {
update_breakdown_checks(scene, checks);
}
if (breakdown_entrances.dataset.entrancesFound != entrances.found) {
update_breakdown_entrances(scene, entrances);
}
}
async function update_breakdown_list(data, changed) {
// Check whether entrances or checks changed
if (changed.checks) {
Object.keys(data.scenes).forEach((scene) =>
update_breakdown(scene, data.scenes[scene], {
found: document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-entrances-title`
).dataset.entrancesFound,
})
);
} else if (changed.entrances) {
Object.keys(data.scenes).forEach((scene) =>
update_breakdown(
scene,
{
collected: document.querySelector(
`.breakdown[data-scene="${scene}"] .breakdown-block-checks-title`
).dataset.checksCollected,
},
data.scenes[scene]
)
);
}
}
async function update_hints(hints) {
let hints_list = document.getElementById("hints-list").cloneNode(true);
let hints_list_item = hints_list.firstElementChild.cloneNode(true);
hints_list.innerHTML = "";
hints_list.appendChild(hints_list_item.cloneNode(true));
hints_list_item.classList.remove("hidden");
// Object.keys(hints).forEach((hint_index) => {
for (const hint_index of Object.keys(hints)) {
// let hint = hints[hint_index].split(
// /(\[[\w\s]+?\]|\"[\w \d\>\<#.\-\']+\"|\<[\w\d#]+\>)/gm
// );
// hint = await Promise.all(
// hint.map(async (segment) => {
// segment = segment.trim();
// if (segment) {
// // if (
// // !(
// // segment.startsWith("[") ||
// // segment.startsWith("<") ||
// // segment.startsWith('"')
// // )
// // ) {
// // segment = translate(segment.trim());
// // } else if (segment.startsWith("[")) {
// // segment = segment.trim();
// // let translated_image_name = image_translations[segment];
// // segment = `<img class="flex object-contain w-8 h-8 my-auto align-middle" src="${translated_image_name}.png"></img>`;
// // } else {
// // segment = ` ${segment.trim()} `;
// // }
// // console.log(segment)
// // return segment;
// return await translate.test_parse_hints(segment, image_translations);
// }
// })
// );
hints[hint_index] = await translate.test_parse_hints(
hints[hint_index],
image_translations
);
}
Object.keys(hints).forEach((hint_index) => {
// let hint = hints[hint_index];
// let matches = Array.from(
// hint.matchAll(/\<([\w\d#]+)\>(.*)(\<[\w\d#]+\>)/gm)
// );
// if (matches.length >= 1) {
// hint = hint.replace(
// /(\<[\w\d#]+\>.*\<[\w\d#]+\>)/gm,
// `<span style="color: ${matches[0][1]};">${matches[0][2]}</span>`
// );
// }
// hint = hint.replace(/ "|" /gm, " ");
hints_list_item.firstElementChild.innerHTML = hints[hint_index];
hints_list.appendChild(hints_list_item.cloneNode(true));
});
document.getElementById("hints-list").innerHTML = "";
document.getElementById("hints-list").replaceWith(hints_list);
}
async function update_scene(scene) {
// Grab current scene and updated scene breakdown/summary elements
const current_breakdown_old = document.querySelector(
`.breakdown[data-current="true"]`
);
const current_breakdown = document.querySelector(
`.breakdown[data-scene="${scene}"]`
);
const current_summary_old = document.querySelector(
`.summary[data-current="true"]`
);
const current_summary = document.querySelector(
`.summary[data-scene="${scene}"]`
);
// Update the current breakdown
current_breakdown_old.dataset.current = false;
current_breakdown_old.classList.add("hidden", "order-last");
current_breakdown_old.classList.remove("order-first");
current_breakdown.dataset.current = true;
current_breakdown.classList.add("order-first");
current_breakdown.classList.remove("hidden", "order-last");
// Update the current summary
current_summary_old.dataset.current = false;
if (hide_completed_areas) {
const checks_remaining = parseInt(
current_summary_old.dataset.checksRemaining
);
const entrances_remaining = parseInt(
current_summary_old.dataset.entrancesRemaining
);
if (checks_remaining > 0 && entrances_remaining > 0) {
current_summary_old.classList.remove("hidden");
} else {
current_summary_old.classList.add("hidden");
}
} else {
current_summary_old.classList.remove("hidden");
}
current_summary.dataset.current = true;
current_summary.classList.add("hidden");
}