index : btroops | |
Virtual board game-aid for BattleTroops, an infantry combat simulator wargame published by FASA in 1989. |
aboutsummaryrefslogtreecommitdiff |
diff options
Diffstat (limited to 'src/modules')
-rw-r--r-- | src/modules/gameboard.js | 60 | ||||
-rw-r--r-- | src/modules/observable.js | 19 | ||||
-rw-r--r-- | src/modules/record_sheet.js | 59 |
3 files changed, 77 insertions, 61 deletions
diff --git a/src/modules/gameboard.js b/src/modules/gameboard.js index abf37b0..8f03603 100644 --- a/src/modules/gameboard.js +++ b/src/modules/gameboard.js @@ -1,8 +1,9 @@ import * as firingArc from './game/firing_arc.js'; import * as sightLine from './game/sight_line.js'; import * as soldier from './game/soldier.js'; +import { Observable } from "./observable"; -let svg, distanceCallback, proneFlagCallback, selectCallback, +let svg, distanceCallback, proneFlagCallback, selected, placing = []; @@ -74,6 +75,17 @@ function getSelected() { return svg.querySelector(`.counter.selected[data-allegiance][data-number]`); } +function deselect() { + const selected = getSelected(); + placing = []; + + if (selected) { + selected.classList.remove(soldier.getSelectedClass()); + clearSightLine(); + firingArc.clipAll(svg); + } +} + function clearSightLine() { sightLine.setHexes([]); sightLine.clear(); @@ -159,7 +171,7 @@ function hasPreviousMoveInHistory(counter) { } function selectOffBoard() { - this.classList.contains(soldier.getSelectedClass()) ? unSelect() : select(this); + Observable.notify('select', this); } export function getUnits() { @@ -174,10 +186,6 @@ export function setProneFlagCallback(callback) { proneFlagCallback = callback; } -export function setSelectCallback(callback) { - selectCallback = callback; -} - export function start(el) { svg = el; @@ -202,10 +210,10 @@ export function start(el) { placing.push(toPlace); getLockedSightLine(svg) ? updateSightLine(toPlace.parentElement) : drawSightLine(toPlace.parentElement, cell); } else { - unSelect(); + deselect(); } } else if (!occupant.classList.contains('clone')) { - select(occupant); + Observable.notify('select', occupant); } else { if (isClone(occupant).of(toPlace)) { if (hasPreviousMoveInHistory(occupant)) { @@ -218,7 +226,7 @@ export function start(el) { placing.push(toPlace); } } else if (!toPlace && occupant) { - select(occupant); + Observable.notify('select', occupant); } else { console.log('removing cell contents'); getCellContents(cell).forEach(el => el.remove()); @@ -234,7 +242,7 @@ export function start(el) { selector = `[data-allegiance="${allegiance}"][data-number="${number}"]`; svg.querySelectorAll(selector).forEach(el => el.remove()); - selectCallback(); + Observable.notify('select'); } }); @@ -271,33 +279,23 @@ export function start(el) { }); }); + Observable.subscribe('select', select); console.log('gameboard.js loaded'); } -export function select(selected) { - unSelect(); - let counter = soldier.getCounter(svg, selected); +export function select(data) { + if (!data) return; - if (counter) { - firingArc.get(svg, counter).forEach(el => el.removeAttribute('clip-path')); - } else { - counter = soldier.createCounter(selected); - } + const counter = soldier.getCounter(svg, data) || soldier.createCounter(data); + const isSelected = counter.classList.contains(soldier.getSelectedClass()); - placing.push(counter); - counter.classList.add(soldier.getSelectedClass()); - selectCallback && selectCallback({ prone: soldier.hasProne(counter), ...counter.dataset }); -} + deselect(); -export function unSelect() { - const selected = getSelected(); - placing = []; + if (isSelected) return; - if (selected) { - getSelected().classList.remove(soldier.getSelectedClass()); - clearSightLine(); - firingArc.clipAll(svg); - } + counter.classList.add(soldier.getSelectedClass()); + firingArc.get(svg, counter).forEach(el => el.removeAttribute('clip-path')); + placing.push(counter); } export function endMove() { @@ -305,7 +303,7 @@ export function endMove() { if (selected) { soldier.endMove(svg, selected); - unSelect(); + deselect(); } } diff --git a/src/modules/observable.js b/src/modules/observable.js new file mode 100644 index 0000000..e4f6797 --- /dev/null +++ b/src/modules/observable.js @@ -0,0 +1,19 @@ +const observers = {}; + +export const Observable = Object.freeze({ + notify: (event, data) => { + observers[event].forEach((observer) => observer(data)) + }, + + subscribe: (event, func) => { + (observers[event] ??= []).push(func); + }, + + unsubscribe: (event, func) => { + [...observers[event] || []].forEach((observer, index) => { + if (observer === func) { + observers[event].splice(index, 1); + } + }); + }, +}); diff --git a/src/modules/record_sheet.js b/src/modules/record_sheet.js index bf28875..7b0a80f 100644 --- a/src/modules/record_sheet.js +++ b/src/modules/record_sheet.js @@ -1,3 +1,5 @@ +import { Observable } from "./observable"; + const weapons = { rifle: { name: 'Rifle', @@ -98,27 +100,19 @@ function createRecords(units) { return grouped; } -function addEventListeners(unSelectCounter, selectCounter) { - document.querySelectorAll('.soldier-record').forEach(el => - el.addEventListener('click', () => { - if (el.classList.contains('selected')) { - el.classList.remove('selected'); - unSelectCounter(); - unSelect(); - } else { - selectCounter(el); - } - }) - ); +function getRecord({ dataset: { allegiance: al, number: n }}) { + const selector = `.soldier-record[data-number="${n}"][data-allegiance="${al}"]`; + + return document.querySelector(selector); } -export function clear() { - document.querySelectorAll('#record-sheet .soldier-record').forEach(el => el.remove()); - document.querySelector('#attacker-record .name').textContent = 'attacker'; - document.querySelector('#defender-record .name').textContent = 'defender'; +function addEventListeners() { + document.querySelectorAll('.soldier-record').forEach(el => + el.addEventListener('click', () => Observable.notify('select', el)) + ); } -export function unSelect() { +function deselect() { const selected = getSelected(); if (selected) { @@ -128,24 +122,28 @@ export function unSelect() { document.getElementById('toggle-prone-counter').checked = false; } -export function getSelected() { - return document.querySelector('.soldier-record.selected'); +function clear() { + document.querySelectorAll('#record-sheet .soldier-record').forEach(el => el.remove()); + document.querySelector('#attacker-record .name').textContent = 'attacker'; + document.querySelector('#defender-record .name').textContent = 'defender'; } -export function select(data) { - unSelect(); +function select(data) { + const record = data && getRecord(data); + const isSelected = record?.classList.contains('selected'); - if (!data) { - return; - } + deselect(); - const { allegiance: al, number: n } = data, - selector = `.soldier-record[data-number="${n}"][data-allegiance="${al}"]`; + if (isSelected || !data) return; - document.querySelector(selector).classList.add('selected'); + record.classList.add('selected'); document.querySelector('#toggle-prone-counter').checked = data.prone; } +export function getSelected() { + return document.querySelector('.soldier-record.selected'); +} + export function endMove() { const selected = getSelected(); @@ -153,10 +151,10 @@ export function endMove() { selected.classList.toggle('movement-ended'); } - unSelect(); + deselect(); } -export function start(startLoc, units, gbUnSelect, gbSelect) { +export function start(startLoc, units) { clear(); const forces = createRecords(units); @@ -171,5 +169,6 @@ export function start(startLoc, units, gbUnSelect, gbSelect) { forces[affiliation].forEach(r => records.appendChild(r)); } - addEventListeners(gbUnSelect, gbSelect); + Observable.subscribe('select', select); + addEventListeners(); } |