index : btroops | |
Virtual board game-aid for BattleTroops, an infantry combat simulator wargame published by FASA in 1989. |
aboutsummaryrefslogtreecommitdiff |
diff options
-rw-r--r-- | public/assets/css/style.css | 2 | ||||
-rw-r--r-- | src/index.js | 109 | ||||
-rw-r--r-- | src/modules/scenario.js | 102 |
3 files changed, 107 insertions, 106 deletions
diff --git a/public/assets/css/style.css b/public/assets/css/style.css index 649b425..5fa37f8 100644 --- a/public/assets/css/style.css +++ b/public/assets/css/style.css @@ -186,13 +186,11 @@ polygon.firing-arc[data-allegiance="attacker"] { stroke: none; } - .soldier-record svg.weapon-icon use { stroke: white; stroke-width: 0.5px; } - .soldier-record svg { width: 20px; height: 20px; diff --git a/src/index.js b/src/index.js index 6b05c03..6b7e930 100644 --- a/src/index.js +++ b/src/index.js @@ -3,6 +3,7 @@ import * as gameboard from './modules/gameboard.js'; import * as recordSheet from './modules/record_sheet.js'; import * as mapSelectDialog from './modules/map_select_dialog.js'; import { Observable } from './modules/observable.js'; +import { requestResource, build } from './modules/scenario.js'; import { scenarios } from './modules/scenarios.js'; globalThis.svgns = 'http://www.w3.org/2000/svg'; @@ -49,121 +50,21 @@ const mapPlaceholder = document.querySelector('.map-placeholder'), let scenarioTemplate; -async function requestResource(url) { - return new Promise((resolve, reject) => { - const request = new XMLHttpRequest(); - request.open('GET', url, true); - request.responseType = 'document'; - - request.onload = function() { - if (request.status === 200) { - resolve(request.response); - } else { - reject(Error('Image didn\'t load successfully; error code:' + request.statusText)); - } - }; - - request.onerror = function() { - reject(Error('There was a network error.')); - }; - - request.send(); - }); -} - -async function loadScript(scenario, svg) { - return new Promise((resolve, reject) => { - const scriptEl = document.createElementNS("http://www.w3.org/2000/svg", 'script'); - - scriptEl.onload = () => { - console.log('map.js loaded'); - resolve(scriptEl); - }; - - scriptEl.onerror = () => { - reject(Error('Script failed to load.')); - }; - - const oldScript = scenario.querySelector('script'); - - if ('cols' in oldScript.dataset && 'rows' in oldScript.dataset) { - scriptEl.dataset.rows = oldScript.dataset.rows; - scriptEl.dataset.cols = oldScript.dataset.cols; - } - - scriptEl.setAttributeNS(null, 'href', '../../map.js'); - svg.append(scriptEl); - }); -} - async function buildScenario(req) { - const svg = scenarioTemplate.querySelector('svg').cloneNode(true); - - document.querySelector('object').contentDocument.querySelector('svg').remove(); - document.querySelector('object').contentDocument.append(svg); - gameboard.stop(); recordSheet.stop(); - const scenario = await req; - const startLocs = scenario.querySelector('.start-locations'); - const gb = svg.querySelector('.gameboard'); - const grid = svg.querySelector('.grid'); - - const externalResourceEls = Array.from(scenario.querySelectorAll('use[href*=".svg"')); - - const refs = externalResourceEls.reduce((acc, el) => { - const href = el.getAttributeNS(null, 'href'); - const [filename] = href.match(/.+\.svg/); - const fragmentIdentifier = href.split('.svg').pop(); - - (acc[filename] ??= new Set()).add(fragmentIdentifier); - el.setAttributeNS(null, 'href', fragmentIdentifier); - - return acc; - }, {}); - - await Promise.all( - Object.keys(refs).map(filename => requestResource(`assets/images/${filename}`)) - ).then(result => { - const defs = svg.querySelector('defs'); - - Object.keys(refs).forEach((filename, index) => { - const external = result[index]; - - refs[filename].forEach(fragmentIdentifier => { - external - .querySelectorAll(`${fragmentIdentifier} use`) - .forEach(el => refs[filename].add(el.getAttributeNS(null, 'href'))); - }); - - const refsQuery = [...refs[filename]].join(', '); - - external.querySelectorAll(refsQuery).forEach(node => - defs.append(svg.ownerDocument.importNode(node, true)) - ); - }); - }); - - scenario.querySelectorAll('use.mapsheet').forEach(el => - gb.querySelector('#background').after(svg.ownerDocument.importNode(el, true)) - ); - - if (startLocs) grid.before(svg.ownerDocument.importNode(startLocs, true)); - - const scenarioGrid = scenario.querySelector('.grid'); + const svg = scenarioTemplate.querySelector('svg').cloneNode(true); + document.querySelector('object').contentDocument.querySelector('svg').replaceWith(svg); - if (scenarioGrid) { - grid.replaceWith(svg.ownerDocument.importNode(scenarioGrid, true)); - } + await build(svg, req); - await loadScript(scenario, svg); mapResourceEl.style.opacity = 1; mapPlaceholder.style.opacity = 0; panzoom.start(svg); gameboard.start(svg); - recordSheet.start(startLocs, gameboard.getUnits()); + recordSheet.start(svg.querySelector('.start-locations'), gameboard.getUnits()); } function updateTurnCounter() { diff --git a/src/modules/scenario.js b/src/modules/scenario.js new file mode 100644 index 0000000..2483bc2 --- /dev/null +++ b/src/modules/scenario.js @@ -0,0 +1,102 @@ +async function loadScript(scenario, svg) { + return new Promise((resolve, reject) => { + const scriptEl = document.createElementNS("http://www.w3.org/2000/svg", 'script'); + + scriptEl.onload = () => { + console.log('map.js loaded'); + resolve(); + }; + + scriptEl.onerror = () => { + reject(Error('Script failed to load.')); + }; + + const dataset = scenario.querySelector('script').dataset; + + if ('cols' in dataset && 'rows' in dataset) { + scriptEl.dataset.rows = dataset.rows; + scriptEl.dataset.cols = dataset.cols; + } + + scriptEl.setAttributeNS(null, 'href', '../../map.js'); + svg.append(scriptEl); + }); +} + +export async function requestResource(url) { + return new Promise((resolve, reject) => { + const request = new XMLHttpRequest(); + request.open('GET', url, true); + request.responseType = 'document'; + + request.onload = function() { + if (request.status === 200) { + resolve(request.response); + } else { + reject(Error('Image didn\'t load successfully; error code:' + request.statusText)); + } + }; + + request.onerror = function() { + reject(Error('There was a network error.')); + }; + + request.send(); + }); +} + +export async function build(svg, request) { + const gb = svg.querySelector('.gameboard'); + const grid = svg.querySelector('.grid'); + + const scenario = await request; + const startLocs = scenario.querySelector('.start-locations'); + const externalResourceEls = Array.from(scenario.querySelectorAll('use[href*=".svg"')); + + const refs = externalResourceEls.reduce((acc, el) => { + const href = el.getAttributeNS(null, 'href'); + const [filename] = href.match(/.+\.svg/); + const fragmentIdentifier = href.split('.svg').pop(); + + (acc[filename] ??= new Set()).add(fragmentIdentifier); + el.setAttributeNS(null, 'href', fragmentIdentifier); + + return acc; + }, {}); + + await Promise.all( + Object.keys(refs).map(filename => requestResource(`assets/images/${filename}`)) + ).then(result => { + const defs = svg.querySelector('defs'); + + Object.keys(refs).forEach((filename, index) => { + const external = result[index]; + + refs[filename].forEach(fragmentIdentifier => { + external + .querySelectorAll(`${fragmentIdentifier} use`) + .forEach(el => refs[filename].add(el.getAttributeNS(null, 'href'))); + }); + + const refsQuery = [...refs[filename]].join(', '); + + external.querySelectorAll(refsQuery).forEach(node => + defs.append(svg.ownerDocument.importNode(node, true)) + ); + }); + }); + + scenario.querySelectorAll('use.mapsheet').forEach(el => + gb.querySelector('#background').after(svg.ownerDocument.importNode(el, true)) + ); + + if (startLocs) grid.before(svg.ownerDocument.importNode(startLocs, true)); + + const scenarioGrid = scenario.querySelector('.grid'); + + if (scenarioGrid) { + grid.replaceWith(svg.ownerDocument.importNode(scenarioGrid, true)); + } + + return loadScript(scenario, svg); +} |