index : btroops | |
Virtual board game-aid for BattleTroops, an infantry combat simulator wargame published by FASA in 1989. |
aboutsummaryrefslogtreecommitdiff |
diff options
author | Catalin Mititiuc <webdevcat@proton.me> | 2024-07-30 21:02:13 -0700 |
---|---|---|
committer | Catalin Mititiuc <webdevcat@proton.me> | 2024-07-30 21:08:00 -0700 |
commit | 1687e0e790d869fe58f86046f5ee093981670c63 (patch) | |
tree | 212e0c3127483ec29774ac237c07e00b26f05086 | |
parent | 48e7675eb0583e420dac52be341e505331c05b4b (diff) |
Ok, hover and firing arc doesn't get stuck at all
Not sure about counters
-rw-r--r-- | public/assets/css/map.css | 7 | ||||
-rw-r--r-- | public/assets/images/scenario_template.svg | 6 | ||||
-rw-r--r-- | src/modules/gameboard.js | 260 | ||||
-rw-r--r-- | src/modules/scenario.js | 3 | ||||
-rw-r--r-- | src/radial.js | 9 |
5 files changed, 200 insertions, 85 deletions
diff --git a/public/assets/css/map.css b/public/assets/css/map.css index feda870..9c0c189 100644 --- a/public/assets/css/map.css +++ b/public/assets/css/map.css @@ -184,7 +184,6 @@ g.counter.selected { g.counter use.primary-weapon { r: inherit; - pointer-events: none; } g.counter use.troop-number, g.counter use.squad-number { @@ -480,7 +479,7 @@ text.elevation { fill: black; } -.grid-top:hover use[href="#hex"] { +[data-q][data-r][data-s][data-t].hover use[href="#hex"] { opacity: 1; fill: orange; stroke: black; @@ -502,12 +501,12 @@ g.counter use[class^="counter-"] { --translateY: calc(var(--y) / 6 - 5px); } -.grid-top .container > g.counter ~ use[class^="counter-"] { +.frontmost > g.counter ~ use[class^="counter-"] { --translateX: calc(var(--x) * 2 - 5px); --translateY: calc(var(--y) * 2 - 5px); } -.grid-top .container > use[class^="counter-"] { +.frontmost > use[class^="counter-"] { --translateX: calc(var(--x) * 1.5 - 5px); --translateY: calc(var(--y) * 1.5 - 5px); } diff --git a/public/assets/images/scenario_template.svg b/public/assets/images/scenario_template.svg index bc5b146..6e4ac14 100644 --- a/public/assets/images/scenario_template.svg +++ b/public/assets/images/scenario_template.svg @@ -70,10 +70,8 @@ <g id="lines"/> </g> - <g class="grid"/> - <g class="grid-top"> - <use href="#hex"/> - <g class="container"/> + <g class="grid"> + <g class="frontmost"/> </g> </g> </svg> diff --git a/src/modules/gameboard.js b/src/modules/gameboard.js index 02b9c0f..3f02784 100644 --- a/src/modules/gameboard.js +++ b/src/modules/gameboard.js @@ -10,6 +10,8 @@ const top = { collection: new Map() }; +const frontmostStore = new Map(); + function getCellContents(cell) { return cell.querySelectorAll('*:not(use[href="#hex"])'); } @@ -215,46 +217,142 @@ function workaroundForWebKitBug233432(listener) { export function start(el) { svg = el; - const gridTop = svg.querySelector('.grid-top'); - top.container = svg.querySelector('.grid-top > .container'); - const topHex = svg.querySelector('.grid-top > use[href="#hex"]'); + //const gridTop = svg.querySelector('.grid-top'); + //top.container = svg.querySelector('.grid-top > .container'); + //const topHex = svg.querySelector('.grid-top > use[href="#hex"]'); + + const grid = svg.querySelector('.grid'); + const frontmost = grid.querySelector('.frontmost'); + + svg.addEventListener('pointerover', e => { + //console.log('pointerover', e.target.closest('[data-q][data-r][data-s][data-t], .frontmost'), e); + const targetCell = e.target.closest('[data-q][data-r][data-s][data-t]'); + console.log('SVG pointerover', targetCell); + const counter = targetCell && targetCell.querySelector('.counter'); + //console.log('pointerover', 'targetCell', targetCell); + + if (counter) { + firingArc.toggleCounterVisibility(svg, counter, true); + frontmost.setAttributeNS(null, 'transform', targetCell.getAttributeNS(null, 'transform')); + frontmostStore.set(counter, targetCell); + frontmost.append(counter); + } - const clearHexDialog = document.querySelector('#clear-hex'); - clearHexDialog.addEventListener('close', e => { - if (clearHexDialog.returnValue === 'confirm') { - [...top.container.children].forEach(child => { - top.collection.delete(child); - child.remove(); + targetCell && targetCell.classList.add('hover'); + + //if (targetCell && !targetCell.classList.contains('frontmost')) { + // targetCell.classList.add('hover'); + // const occupant = targetCell.querySelector('.counter'); + // + // if (occupant) { + // firingArc.toggleCounterVisibility(svg, occupant, true); + // } + // const children = [...targetCell.children].filter(c => c.getAttributeNS(null, 'href') !== '#hex'); + // if (children.length > 0) { + // frontmost.setAttributeNS(null, 'transform', targetCell.getAttributeNS(null, 'transform')); + // children.forEach(child => { + // frontmostStore.set(child, targetCell); + // frontmost.append(child); + // }); + // } + //} + //console.log('frontmost contents', frontmost.children); + }); + + svg.addEventListener('pointerout', e => { + //const targetCell = e.target.closest('[data-q][data-r][data-s][data-t], .frontmost'); + console.log('pointer out target', e.target); + const targetCell = e.target.closest('[data-q][data-r][data-s][data-t], .frontmost'); + + if (targetCell) { + console.log('SVG pointerout', targetCell); + [...frontmost.children].forEach(child => { + //console.log('child', child, 'relatedTarget', e.relatedTarget); + //if ([ + // !e.relatedTarget, // out of the window + // targetCell.classList.contains('frontmost') && !e.relatedTarget.closest('.frontmost'), // from one element in frontmost to another element in frontmost + // !targetCell.classList.contains('frontmost') && frontmostStore.get(child) === targetCell, // leaving from a hex under frontmost + //].some(e => e)) { + console.log('child', child, 'belongs to', frontmostStore.get(child)); + console.log('relatedTarget', e.relatedTarget); + if (!e.relatedTarget || frontmostStore.get(child) !== targetCell || (e.relatedTarget !== child && !child.contains(e.relatedTarget))) { + //if (!e.relatedTarget || frontmostStore.get(child) !== targetCell || e.relatedTarget !== child) { + const parent = frontmostStore.get(child); + console.log('returning to', parent); + //console.log('RETURNING to', parent); + parent.append(child); + + //if (child.classList.contains('.counter')) { + // firingArc.toggleCounterVisibility(svg, child, false); + //} + + firingArc.toggleCounterVisibility(svg, child, false); + parent.classList.remove('hover'); + frontmostStore.delete(child); + } + }); + //targetCell.classList.remove('hover'); + if (frontmost.children.length < 1) targetCell.classList.remove('hover'); + } else { + [...frontmost.children].forEach(child => { + const parent = frontmostStore.get(child); + parent.append(child); + parent.classList.remove('hover'); + frontmostStore.delete(child); }); } + //console.log('frontmost contents', frontmost.children); }); - clearHexDialog.querySelector('button[value="confirm"]').addEventListener('click', function(e) { - e.preventDefault(); - clearHexDialog.close(this.value); + grid.addEventListener('click', e => { + console.log('click', e.target); }); - gridTop.addEventListener('pointerleave', workaroundForWebKitBug233432(e => { - [...top.container.children].forEach(child => { - top.collection.get(child).parent.append(child); - top.collection.delete(child); - }); - - top.cell = null; - })); - - topHex.addEventListener('click', clickHandler); - - topHex.addEventListener('contextmenu', e => { - e.preventDefault(); - getSelected() ? sightLine.toggleLock(top.cell) : clearHexDialog.showModal(); - }); + const clearHexDialog = document.querySelector('#clear-hex'); + //clearHexDialog.addEventListener('close', e => { + // if (clearHexDialog.returnValue === 'confirm') { + // [...top.container.children].forEach(child => { + // top.collection.delete(child); + // child.remove(); + // }); + // } + //}); + + //clearHexDialog.querySelector('button[value="confirm"]').addEventListener('click', function(e) { + // e.preventDefault(); + // clearHexDialog.close(this.value); + //}); + + //gridTop.addEventListener('pointerleave', workaroundForWebKitBug233432(e => { + // console.log('pointerleave top', performance.now(), top.cell); + // const occupant = svg.querySelector('.grid-top .container .counter'); + // + // if (occupant) { + // firingArc.toggleCounterVisibility(svg, occupant, false); + // } + // + // [...top.container.children].forEach(child => { + // top.collection.get(child).parent.append(child); + // top.collection.delete(child); + // }); + // + // top.cell = null; + // + // getActiveSightLine(svg) && clearSightLine(); + //})); + + //topHex.addEventListener('click', clickHandler); + // + //topHex.addEventListener('contextmenu', e => { + // e.preventDefault(); + // getSelected() ? sightLine.toggleLock(top.cell) : clearHexDialog.showModal(); + //}); const startingLocations = svg.querySelector('.start-locations'); startingLocations && getUnits(startingLocations).forEach(unit => unit.addEventListener('click', selectOffBoard)); function clickHandler(e) { - const occupant = svg.querySelector('.grid-top .container .counter') + const occupant = svg.querySelector('.grid-top .container .counter'); let toPlace = placing.pop(); if (isCounter(toPlace) || isMechTemplate(toPlace)) { @@ -280,43 +378,47 @@ export function start(el) { const selected = getSelected(); } - getCells(svg).forEach(cell => { - cell.addEventListener('pointerover', () => { - //console.log(['pointerenter', cell]); - - top.cell = cell; - - [...top.container.children].forEach(child => { - top.collection.get(child).parent.append(child); - top.collection.delete(child); - }); - - top.container.parentElement.setAttributeNS(null, 'transform', cell.getAttributeNS(null, 'transform')); - - [...cell.children].filter(c => c.getAttributeNS(null, 'href') !== '#hex').forEach(child => { - top.collection.set(child, { parent: cell }); - top.container.append(child); - }); - - let occupant = svg.querySelector('.grid-top .container .counter'); - const selected = getSelected(); - - if (placing[0]?.getAttributeNS(null, 'class') == 'mech-template') { - cell.appendChild(placing[0]); - } - - if (selected && svg.querySelector('.grid').contains(selected) && !getLockedSightLine(svg) && cell !== selected.parentElement) { - clearSightLine(); - drawSightLine(selected.parentElement, cell); - } - - occupant = getCellOccupant(cell); - - if (occupant) { - firingArc.toggleCounterVisibility(svg, occupant, true); - } - }); - }); + //getCells(svg).forEach(cell => { + // cell.addEventListener('pointerleave', () => { + // console.log('pointerleave cell', performance.now(), cell); + // }); + // + // cell.addEventListener('pointerover', () => { + // console.log('pointerenter', performance.now(), cell); + // + // top.cell = cell; + // + // [...top.container.children].forEach(child => { + // top.collection.get(child).parent.append(child); + // top.collection.delete(child); + // }); + // + // top.container.parentElement.setAttributeNS(null, 'transform', cell.getAttributeNS(null, 'transform')); + // + // [...cell.children].filter(c => c.getAttributeNS(null, 'href') !== '#hex').forEach(child => { + // top.collection.set(child, { parent: cell }); + // top.container.append(child); + // }); + // + // let occupant = svg.querySelector('.grid-top .container .counter'); + // const selected = getSelected(); + // + // if (placing[0]?.getAttributeNS(null, 'class') == 'mech-template') { + // cell.appendChild(placing[0]); + // } + // + // if (selected && svg.querySelector('.grid').contains(selected) && !getLockedSightLine(svg) && cell !== selected.parentElement) { + // clearSightLine(); + // drawSightLine(selected.parentElement, cell); + // } + // + // occupant = getCellOccupant(cell); + // + // if (occupant) { + // firingArc.toggleCounterVisibility(svg, occupant, true); + // } + // }); + //}); //const cell = document.querySelector('[data-q="0"][data-r="0"][data-s="0"][data-t="0"]'); //const povr = new PointerEvent('pointerover'); @@ -326,17 +428,29 @@ export function start(el) { // debug // // Add a trooper counter - //const attacker = { dataset: { allegiance: 'attacker', number: 1, squad: 1 }}; // const defender = { dataset: { allegiance: 'defender', number: 1, squad: 2 }}; - //const cell = getCell(0, 0, 0, 0); - //const trooper = soldier.createCounter(attacker, 'blazer'); - //const trooperSack = document.createElementNS(svgns, 'g'); - //trooperSack.classList.add('cell-contents'); - //trooperSack.append(trooper); - //soldier.place(svg, trooper, cell); + + const cell = getCell(0, 0, 0, 0); + const attacker = { dataset: { allegiance: 'attacker', number: 1, squad: 1 }}; + const trooper = soldier.createCounter(attacker, 'blazer'); + soldier.place(svg, trooper, cell); // Add some counters in an unoccupied cell //const countersCell = getCell(-1, 1, 0, 0); + const counter = document.createElementNS(svgns, 'use'); + const name = 'grenade'; + //counter.addEventListener('click', e => { + // e.stopPropagation() + // const container = counter.parentElement; + // counter.remove() + // arrangeCounters(container); + //}); + + //counter.setAttributeNS(null, 'href', `#counter-${name}`); + //counter.classList.add(`counter-${name}`); + //cell.append(counter); + //arrangeCounters(cell) + //setCounter('grenade'); //setCounter('prone'); //setCounter('1st-floor'); @@ -374,7 +488,7 @@ export function setFiringArc() { isOnBoard = counter => counter && counter.parentElement.hasAttribute('data-q'); if (isOnBoard(counter)) { - returnToParent(top); + //returnToParent(top); firingArc.set(svg, this.dataset.size, counter, getCellPosition(counter.parentElement)); } } diff --git a/src/modules/scenario.js b/src/modules/scenario.js index 805d0fe..4f72168 100644 --- a/src/modules/scenario.js +++ b/src/modules/scenario.js @@ -97,7 +97,8 @@ export async function build(svg, request) { const scenarioBuildings = scenario.querySelector('.gameboard .buildings'); if (scenarioGrid) { - grid.replaceWith(svg.ownerDocument.importNode(scenarioGrid, true)); + const frontmost = grid.querySelector('.frontmost'); + [...scenarioGrid.children].forEach(child => frontmost.before(svg.ownerDocument.importNode(child, true))); } if (scenarioBuildings) diff --git a/src/radial.js b/src/radial.js index 09037ab..7c7c0f3 100644 --- a/src/radial.js +++ b/src/radial.js @@ -1,5 +1,6 @@ const xmlns = 'http://www.w3.org/2000/svg'; const grid = document.querySelector('svg .grid'); +const frontmost = grid.querySelector('.frontmost'); const hex = { inradius: 8.66, @@ -247,10 +248,10 @@ function drawBuildings(buildings, container, { q: pq, r: pr, s: ps }, features) }, new Map()); } -function drawMapsheet(gameboard, mapsheet, position) { +function drawMapsheet(placementMarker, mapsheet, position) { const container = document.createElementNS(xmlns, 'g'); container.classList.add(mapsheet.id); - gameboard.appendChild(container); + placementMarker.before(container); const buildingContainer = document.createElementNS(xmlns, 'g'); buildingContainer.classList.add(mapsheet.id); @@ -440,11 +441,13 @@ findScalar(findMult(sheets), +width + 1, +height).forEach(([vscalar, row]) => { return vectorAdd(coords, { q: -1, r: 0, s: 1 }, hscalar); } - ms = drawMapsheet(grid, ms, horzMapVect(vertMapVect({ q: 0, r: 0, s: 0 }))); + ms = drawMapsheet(frontmost, ms, horzMapVect(vertMapVect({ q: 0, r: 0, s: 0 }))); finalGrid = new Map([...finalGrid, ...ms]); }) }); +document.querySelector('.grid .mapsheets').remove(); + function addGroup(container, className) { const g = document.createElementNS(xmlns, 'g'); g.classList.add(className); |