index : btroops | |
Virtual board game-aid for BattleTroops, an infantry combat simulator wargame published by FASA in 1989. |
aboutsummaryrefslogtreecommitdiff |
diff options
-rw-r--r-- | src/index.js | 6 | ||||
-rw-r--r-- | src/modules/counter.js | 232 | ||||
-rw-r--r-- | src/modules/game.js | 54 |
3 files changed, 61 insertions, 231 deletions
diff --git a/src/index.js b/src/index.js index 89893b6..b4216be 100644 --- a/src/index.js +++ b/src/index.js @@ -121,7 +121,8 @@ window.addEventListener('load', () => { game.unSelect(); RecordSheet.unSelect(); } else { - game.select(el.dataset.troopAllegiance, el.dataset.troopNumber); + const { troopAllegiance: allegiance, troopNumber: number } = el.dataset; + game.select({ dataset: { allegiance, number }}); } }) ); @@ -156,7 +157,8 @@ window.addEventListener('load', () => { .forEach(el => el.classList.remove('movement-ended')); game.endTurn(allegiance); - game.select(records.at(0).dataset.troopAllegiance, records.at(0).dataset.troopNumber); + const { troopAllegiance, troopNumber } = records.at(0).dataset; + game.select({ dataset: { allegiance: troopAllegiance, number: troopNumber }}); }) ); diff --git a/src/modules/counter.js b/src/modules/counter.js index 416ddb3..f7b1d56 100644 --- a/src/modules/counter.js +++ b/src/modules/counter.js @@ -1,11 +1,10 @@ -const svgns = "http://www.w3.org/2000/svg", - selectedClass = 'selected'; +const svgns = "http://www.w3.org/2000/svg"; export default class Counter { - constructor(svg, container) { + constructor(svg) { this.svg = svg; - this.container = container; + this.selectedClass = 'selected'; } dataSelector(troopNumber, allegiance) { @@ -61,178 +60,12 @@ export default class Counter { return pt; } - // pointerOver(e) { - // const { number: troopNumber, allegiance: troopAllegiance } = e.target.dataset, - // cp = this.svg.querySelector(`#clip-path-${troopAllegiance}-${troopNumber}`); - - // if (cp) { - // cp.style.display = 'none'; - // } - // } - - // pointerOut(e) { - // let { number: troopNumber, allegiance: troopAllegiance } = e.target.dataset, - // cp = this.svg.querySelector(`#clip-path-${troopAllegiance}-${troopNumber}`); - - // if (cp) { - // let isVisible = - // document - // .getElementById('toggle-firing-arc-vis') - // .querySelector(`input[data-allegiance="${troopAllegiance}"]`) - // .checked; - - // cp.style.display = isVisible ? 'none' : ''; - // } - // } - - click(e) { - if (e.target.classList.contains(selectedClass)) { - e.stopPropagation(); - let { number: troopNumber, allegiance: troopAllegiance } = e.target.dataset, - trace = this.svg.querySelector(this.traceSelector(troopNumber, troopAllegiance)); - - if (trace) { - let points = trace.getAttribute('points').split(' '), - [clonePosX, clonePosY] = points.at(-2).split(',').map(p => parseFloat(p)), - - { clone } = Array - .from(this.getClones(troopAllegiance, troopNumber)) - .map(c => { return { clone: c, pos: this.getCellPosition(c.parentElement) }}) - .find(({ pos: { x, y }}) => x == clonePosX && y == clonePosY); - - points.pop(); - - if (points.length >= 2) { - trace.setAttributeNS(null, 'points', points.join(' ')); - } else { - trace.remove(); - } - - let sl = this.svg.querySelector('.sight-line'); - - if (sl) { - this.container.sightLine.update(clone, this.getCellPosition(clone.parentElement)); - } else { - this.container.sightLine.draw(e.target.parentElement, clone.parentElement); - } - - const proneCounter = e.target.parentElement.querySelector('[href="#counter-prone"]'); - - if (proneCounter) { - proneCounter.remove(); - } - - this.container.proneFlagCallback(!!clone.parentElement.querySelector('[href="#counter-prone"]')); - - clone.parentElement.appendChild(e.target); - clone.remove(); - } - } else { - e.stopPropagation(); - this.select(e.target); - } + getBoard() { + return this.svg.querySelector('.board'); } - clickClone(e) { - e.stopPropagation(); - - let { number: troopNumber, allegiance: troopAllegiance } = e.target.dataset, - pos = this.getCellPosition(e.target.parentElement); - - if (this.isSelected(troopNumber, troopAllegiance)) { - let trace = this.svg.querySelector(this.traceSelector(troopNumber, troopAllegiance)), - points = trace.getAttribute('points').split(' '); - - if (`${pos.x},${pos.y}` == points.at(0)) { - const counter = this.getCounter(troopAllegiance, troopNumber), - lockedSl = this.svg.querySelector('.sight-line:not(.active)'); - - if (!lockedSl) { - this.container.sightLine.clear(); - } else { - this.container.sightLine.update(e.target, this.container.getCellPosition(e.target.parentElement)); - } - - this.container.proneFlagCallback(!!e.target.parentElement.querySelector('[href="#counter-prone"]')); - - e.target.parentElement.appendChild(counter); - e.target.remove(); - this.removeClones(counter); - trace.remove(); - } else { - const proneCounter = e.target.parentElement.querySelector('[href="#counter-prone"]'); - - if (proneCounter) { - proneCounter.remove(); - } - - points = points.filter(p => p != `${pos.x},${pos.y}`).join(' '); - trace.setAttributeNS(null, 'points', points); - e.target.remove(); - } - } - } - - dblClick(e) { - if (e.target.classList.contains(selectedClass)) { - let { troopNumber, troopAllegiance } = e.target.dataset, - trace = this.svg.querySelector(this.traceSelector(troopNumber, troopAllegiance)); - - if (!trace) { - e.target.remove(); - this.svg.querySelectorAll(`#firing-arcs ${this.dataSelector(troopNumber, troopAllegiance)}`).forEach(el => el.remove()); - } - } - } - - select({ dataset: { allegiance, number }}) { - this.unSelect(); - - let counter = this.getCounter(allegiance, number); - - if (counter) { - counter.classList.add(selectedClass); - let existingArcs = this.container.getExistingArcs(allegiance, number); - existingArcs.forEach(el => el.removeAttribute('clip-path')); - this.container.selectCallback({ prone: this.hasProne(counter), ...counter.dataset }); - } - } - - unSelect() { - let selected = this.container.getSelected(); - - if (selected) { - let { troopNumber, troopAllegiance } = selected.dataset; - - selected.classList.remove(selectedClass); - selected.removeAttribute('style'); - this.container.sightLine.clear(); - - this - .svg - .querySelectorAll(`${this.selector(troopNumber, troopAllegiance)}.clone`) - .forEach(el => el.removeAttribute('style')); - } - - this.container.clipFiringArcs(); - } - - get(troopNumber, allegiance) { - return this.container.getCounter(allegiance, troopNumber); - } - - getAt(x, y) { - return this.container.querySelector(`${counterPosition(x, y)}:not(.clone)`); - } - - isSelected(troopNumber, allegiance) { - return this.container.svg.querySelector(`${this.selector(troopNumber, allegiance)}.${selectedClass}`) !== null; - } - - place(point) { - const selected = this.container.getSelected(), - troopAllegiance = selected.dataset.allegiance, - troopNumber = selected.dataset.number; + place(selected, cell) { + const { allegiance: troopAllegiance, number: troopNumber } = selected.dataset; let points, counterNodeList = this.getCounterAndClones(troopAllegiance, troopNumber); @@ -246,12 +79,12 @@ export default class Counter { ] let clone = selected.cloneNode(true); - clone.classList.remove(selectedClass); + clone.classList.remove(this.selectedClass); clone.classList.add('clone'); selected.dataset.previous = prevCoords; selected.parentElement.appendChild(clone); - point.parentElement.appendChild(selected); + cell.appendChild(selected); selected.childNodes.forEach(n => { if (n.classList.contains('removed')) { @@ -273,25 +106,18 @@ export default class Counter { trace.dataset.allegiance = troopAllegiance; trace.classList.add('move-trace'); - this.container.getBoard().prepend(trace); + this.getBoard().prepend(trace); } else { points = `${trace.getAttribute('points')} ${current.x},${current.y}`; } trace.setAttributeNS(null, 'points', points); - // clone.addEventListener('click', this.clickClone.bind(this)); } else { selected.removeAttribute('data-x'); - point.parentElement.appendChild(selected); + cell.appendChild(selected); } } - remove({ dataset: { troopNumber, troopAllegiance }}) { - this.container - .querySelectorAll(dataSelector(troopNumber, troopAllegiance)) - .forEach(el => el.remove()); - } - removeClones({ dataset: { allegiance, number }}) { this.getClones(allegiance, number).forEach(el => { el.remove() @@ -314,37 +140,23 @@ export default class Counter { } this.removeClones(el); - this.unSelect(); } hasProne(counter) { - const isOnBoard = counter.parentElement.hasAttribute('data-x'); - - if (isOnBoard) { - return !!counter.querySelector('[href="#counter-prone"]'); - } - - return false; + return !!counter.querySelector('[href="#counter-prone"]'); } - toggleProne() { - const selected = this.container.getSelected(), - isOnBoard = selected && selected.parentElement.hasAttribute('data-x'); + toggleProne(counter) { + let proneCounter = counter.querySelector('[href="#counter-prone"]'); - if (selected && isOnBoard) { - const proneCounter = selected.querySelector('[href="#counter-prone"]'); - - if (proneCounter) { - if ('preexisting' in proneCounter.dataset) { - proneCounter.classList.toggle('removed'); - } else { - proneCounter.remove(); - } - } else { - const counter = document.createElementNS(svgns, 'use'); - counter.setAttributeNS(null, 'href', '#counter-prone'); - selected.appendChild(counter); - } + if (!proneCounter) { + proneCounter = document.createElementNS(svgns, 'use'); + proneCounter.setAttributeNS(null, 'href', '#counter-prone'); + counter.appendChild(proneCounter); + } else if ('preexisting' in proneCounter.dataset) { + proneCounter.classList.toggle('removed'); + } else { + proneCounter.remove(); } } } diff --git a/src/modules/game.js b/src/modules/game.js index e40a8a2..d6059ae 100644 --- a/src/modules/game.js +++ b/src/modules/game.js @@ -17,7 +17,7 @@ export default class Game { this.svg = svg; this.firingArc = new FiringArc(svg); this.sightLine = new SightLine(svg); - this.counter = new Counter(svg, this); + this.counter = new Counter(svg); this.setUpCells(); } @@ -95,17 +95,31 @@ export default class Game { if (selected) { this.counter.endMove(selected); + this.unSelect(); } } - select(allegiance, number) { - this.placing.push(this.counter.getCounter(allegiance, number)); - this.counter.select({ dataset: { allegiance, number } }); + select({ dataset: { allegiance, number } }) { + const counter = this.counter.getCounter(allegiance, number); + + if (counter) { + this.unSelect(); + this.placing.push(counter); + counter.classList.add(this.counter.selectedClass); + this.getExistingArcs(allegiance, number).forEach(el => el.removeAttribute('clip-path')); + this.selectCallback({ prone: this.counter.hasProne(counter), ...counter.dataset }); + } } unSelect() { - this.placing = []; - this.counter.unSelect(); + const selected = this.getSelected(); + + if (selected) { + this.placing = []; + this.getSelected().classList.remove(this.counter.selectedClass); + this.sightLine.clear(); + this.clipFiringArcs(); + } } endTurn(allegiance) { @@ -114,7 +128,12 @@ export default class Game { } toggleProne() { - this.counter.toggleProne(); + const selected = this.getSelected(), + isOnBoard = selected && selected.parentElement.hasAttribute('data-x'); + + if (selected && isOnBoard) { + this.counter.toggleProne(selected); + } } toggleFiringArcVisibility(allegiance) { @@ -166,12 +185,14 @@ export default class Game { contents: this.getCellContents(cell) }; + console.log(state); + let toPlace = this.placing.pop(); if (isGrenade(toPlace)) { state.hex.after(toPlace); } else if (toPlace && !state.occupant) { - this.counter.place(this.getHex(cell)); + this.counter.place(toPlace, cell); this.placing.push(toPlace); const lockedSl = this.svg.querySelector('.sight-line:not(.active)'); @@ -187,7 +208,7 @@ export default class Game { toPlace.remove(); toPlace = this.getCounterAtGridIndex(...toPlace.dataset.previous.split(',')); toPlace.classList.remove('clone'); - toPlace.classList.add('selected'); + toPlace.classList.add(this.counter.selectedClass); if (!('previous' in toPlace.dataset)) { trace.remove(); } else { @@ -204,16 +225,15 @@ export default class Game { this.sightLine.update(toPlace.parentElement, this.getCellPosition(toPlace.parentElement)); } } else { - this.counter.unSelect(); + this.unSelect(); } } else if (!state.occupant.classList.contains('clone')) { - this.counter.select(state.occupant); - this.placing.push(state.occupant); + this.select(state.occupant); } else { if (isClone(state.occupant).of(toPlace)) { if (!('previous' in state.occupant.dataset)) { state.occupant.classList.remove('clone'); - state.occupant.classList.add('selected'); + state.occupant.classList.add(this.counter.selectedClass); toPlace.remove(); toPlace = state.occupant; this.counter.removeClones(toPlace); @@ -246,27 +266,23 @@ export default class Game { this.placing.push(toPlace); } } else if (!toPlace && state.occupant) { - this.counter.select(state.occupant); - this.placing.push(state.occupant); + this.select(state.occupant); } else { console.log('removing cell contents'); state.contents.forEach(el => el.remove()); } }); - cell.addEventListener('dblclick', e => { const toPlace = this.placing.pop(), occupant = this.getCellOccupant(cell); - if (toPlace == occupant) { + if (toPlace && occupant && toPlace == occupant) { const { number, allegiance } = toPlace.dataset, selector = `[data-allegiance="${allegiance}"][data-number="${number}"]`; this.svg.querySelectorAll(selector).forEach(el => el.remove()); } - - this.unSelect(); }); // Logic for this event: |