Add critical hits, victory celebrations, and enhanced match settings
This commit is contained in:
+79
-14
@@ -1,7 +1,8 @@
|
||||
import { NICKNAME_LENGTH } from "../constants.js";
|
||||
import { DEFAULT_SPAWN_PLACEMENT, NICKNAME_LENGTH } from "../constants.js";
|
||||
|
||||
const STORAGE_KEYS = {
|
||||
names: "arena.match.playerNames",
|
||||
spawnPlacement: "arena.match.spawnPlacement",
|
||||
teamSize: "arena.match.teamSize",
|
||||
};
|
||||
|
||||
@@ -11,22 +12,42 @@ export function createMatchForm() {
|
||||
const appNode = document.querySelector("#app");
|
||||
const statusNode = document.querySelector("#match-status");
|
||||
const statusTextNodes = document.querySelectorAll("[data-status-text]");
|
||||
const spawnPlacementInputs = getElements('input[name="spawnPlacement"]');
|
||||
const teamSizeInput = getElement("#team-size");
|
||||
const teamSizeOutput = getElement("#team-size-value");
|
||||
const teamSizeNumberInput = getElement("#team-size-value");
|
||||
|
||||
const readMatchConfig = () => ({
|
||||
names: nicknameValues(namesInput.value),
|
||||
spawnPlacement: selectedSpawnPlacement(spawnPlacementInputs),
|
||||
teamSize: Number(teamSizeInput.value),
|
||||
});
|
||||
|
||||
restoreSavedMatchSettings(namesInput, teamSizeInput);
|
||||
syncTeamSizeOutput(teamSizeInput, teamSizeOutput);
|
||||
restoreSavedMatchSettings(namesInput, spawnPlacementInputs, teamSizeInput, teamSizeNumberInput);
|
||||
syncTeamSizeInputs(teamSizeInput, teamSizeNumberInput);
|
||||
namesInput.addEventListener("input", () => {
|
||||
saveMatchSettings(namesInput, teamSizeInput);
|
||||
saveMatchSettings(namesInput, spawnPlacementInputs, teamSizeInput);
|
||||
});
|
||||
teamSizeInput.addEventListener("input", () => {
|
||||
syncTeamSizeOutput(teamSizeInput, teamSizeOutput);
|
||||
saveMatchSettings(namesInput, teamSizeInput);
|
||||
syncTeamSizeInputs(teamSizeInput, teamSizeNumberInput);
|
||||
saveMatchSettings(namesInput, spawnPlacementInputs, teamSizeInput);
|
||||
});
|
||||
teamSizeNumberInput.addEventListener("input", () => {
|
||||
if (syncTeamSizeInputs(teamSizeInput, teamSizeNumberInput, teamSizeNumberInput.value)) {
|
||||
saveMatchSettings(namesInput, spawnPlacementInputs, teamSizeInput);
|
||||
}
|
||||
});
|
||||
teamSizeNumberInput.addEventListener("change", () => {
|
||||
syncTeamSizeInputs(
|
||||
teamSizeInput,
|
||||
teamSizeNumberInput,
|
||||
teamSizeNumberInput.value || teamSizeInput.value,
|
||||
);
|
||||
saveMatchSettings(namesInput, spawnPlacementInputs, teamSizeInput);
|
||||
});
|
||||
spawnPlacementInputs.forEach((input) => {
|
||||
input.addEventListener("change", () => {
|
||||
saveMatchSettings(namesInput, spawnPlacementInputs, teamSizeInput);
|
||||
});
|
||||
});
|
||||
|
||||
return {
|
||||
@@ -62,6 +83,16 @@ function getElement(selector) {
|
||||
return element;
|
||||
}
|
||||
|
||||
function getElements(selector) {
|
||||
const elements = [...document.querySelectorAll(selector)];
|
||||
|
||||
if (elements.length === 0) {
|
||||
throw new Error(`Missing required elements: ${selector}`);
|
||||
}
|
||||
|
||||
return elements;
|
||||
}
|
||||
|
||||
function nicknameValues(value) {
|
||||
return value
|
||||
.split(/\r?\n|,/)
|
||||
@@ -69,11 +100,25 @@ function nicknameValues(value) {
|
||||
.filter(Boolean);
|
||||
}
|
||||
|
||||
function syncTeamSizeOutput(input, output) {
|
||||
output.textContent = input.value;
|
||||
function syncTeamSizeInputs(rangeInput, numberInput, value = rangeInput.value) {
|
||||
const normalizedTeamSize = normalizeTeamSize(value, rangeInput);
|
||||
|
||||
if (!normalizedTeamSize) {
|
||||
return "";
|
||||
}
|
||||
|
||||
rangeInput.value = normalizedTeamSize;
|
||||
numberInput.value = normalizedTeamSize;
|
||||
|
||||
return normalizedTeamSize;
|
||||
}
|
||||
|
||||
function restoreSavedMatchSettings(namesInput, teamSizeInput) {
|
||||
function restoreSavedMatchSettings(
|
||||
namesInput,
|
||||
spawnPlacementInputs,
|
||||
teamSizeInput,
|
||||
teamSizeNumberInput,
|
||||
) {
|
||||
const storage = getLocalStorage();
|
||||
|
||||
if (!storage) {
|
||||
@@ -82,6 +127,7 @@ function restoreSavedMatchSettings(namesInput, teamSizeInput) {
|
||||
|
||||
try {
|
||||
const savedNames = storage.getItem(STORAGE_KEYS.names);
|
||||
const savedSpawnPlacement = storage.getItem(STORAGE_KEYS.spawnPlacement);
|
||||
const savedTeamSize = storage.getItem(STORAGE_KEYS.teamSize);
|
||||
|
||||
if (savedNames !== null) {
|
||||
@@ -90,15 +136,19 @@ function restoreSavedMatchSettings(namesInput, teamSizeInput) {
|
||||
|
||||
const normalizedTeamSize = normalizeTeamSize(savedTeamSize, teamSizeInput);
|
||||
|
||||
if (normalizedTeamSize) {
|
||||
teamSizeInput.value = normalizedTeamSize;
|
||||
}
|
||||
syncTeamSizeInputs(
|
||||
teamSizeInput,
|
||||
teamSizeNumberInput,
|
||||
normalizedTeamSize || teamSizeInput.value,
|
||||
);
|
||||
|
||||
setSpawnPlacement(spawnPlacementInputs, savedSpawnPlacement);
|
||||
} catch {
|
||||
// Storage may be unavailable in private or restricted browser contexts.
|
||||
}
|
||||
}
|
||||
|
||||
function saveMatchSettings(namesInput, teamSizeInput) {
|
||||
function saveMatchSettings(namesInput, spawnPlacementInputs, teamSizeInput) {
|
||||
const storage = getLocalStorage();
|
||||
|
||||
if (!storage) {
|
||||
@@ -107,12 +157,27 @@ function saveMatchSettings(namesInput, teamSizeInput) {
|
||||
|
||||
try {
|
||||
storage.setItem(STORAGE_KEYS.names, namesInput.value);
|
||||
storage.setItem(STORAGE_KEYS.spawnPlacement, selectedSpawnPlacement(spawnPlacementInputs));
|
||||
storage.setItem(STORAGE_KEYS.teamSize, normalizeTeamSize(teamSizeInput.value, teamSizeInput));
|
||||
} catch {
|
||||
// Ignore storage failures so the match form remains usable.
|
||||
}
|
||||
}
|
||||
|
||||
function selectedSpawnPlacement(inputs) {
|
||||
return inputs.find((input) => input.checked)?.value ?? DEFAULT_SPAWN_PLACEMENT;
|
||||
}
|
||||
|
||||
function setSpawnPlacement(inputs, value) {
|
||||
const savedInput = inputs.find((input) => input.value === value);
|
||||
const defaultInput = inputs.find((input) => input.value === DEFAULT_SPAWN_PLACEMENT);
|
||||
const nextInput = savedInput ?? defaultInput;
|
||||
|
||||
if (nextInput) {
|
||||
nextInput.checked = true;
|
||||
}
|
||||
}
|
||||
|
||||
function normalizeTeamSize(value, input) {
|
||||
const min = Number(input.min) || 1;
|
||||
const max = Number(input.max) || min;
|
||||
|
||||
Reference in New Issue
Block a user