Create record sheet dynamically when map is loaded
This commit is contained in:
41
src/index.js
41
src/index.js
@@ -16,6 +16,35 @@ object.addEventListener('load', function (e) {
|
||||
const svg = this.contentDocument.querySelector('svg');
|
||||
panzoom.start(svg);
|
||||
gameboard.start(svg);
|
||||
|
||||
recordSheet.clear();
|
||||
|
||||
const recordTemplate = document.querySelector('template#soldier-record-block');
|
||||
const startLoc = svg.querySelector('.start-locations');
|
||||
const forces = recordSheet.createRecords(gameboard.getUnits(), recordTemplate);
|
||||
|
||||
for (const affiliation in forces) {
|
||||
const container = document.querySelector(`#${affiliation}-record`);
|
||||
const name = startLoc.dataset[`${affiliation}Name`];
|
||||
if (name) {
|
||||
container.querySelector('.name').textContent = name;
|
||||
}
|
||||
forces[affiliation].forEach(r => container.appendChild(r));
|
||||
}
|
||||
|
||||
document.querySelectorAll('.soldier-record').forEach(el =>
|
||||
el.addEventListener('click', () => {
|
||||
if (el.classList.contains('selected')) {
|
||||
el.classList.remove('selected');
|
||||
gameboard.unSelect();
|
||||
recordSheet.unSelect();
|
||||
} else {
|
||||
gameboard.select(el);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
window.game = gameboard;
|
||||
});
|
||||
|
||||
gameboard.setDistanceCallback((count = '-') => {
|
||||
@@ -26,18 +55,6 @@ gameboard.setDistanceCallback((count = '-') => {
|
||||
gameboard.setProneFlagCallback(checked => proneToggle.checked = checked);
|
||||
gameboard.setSelectCallback(data => recordSheet.select(data));
|
||||
|
||||
document.querySelectorAll('.soldier-record').forEach(el =>
|
||||
el.addEventListener('click', () => {
|
||||
if (el.classList.contains('selected')) {
|
||||
el.classList.remove('selected');
|
||||
gameboard.unSelect();
|
||||
recordSheet.unSelect();
|
||||
} else {
|
||||
gameboard.select(el);
|
||||
}
|
||||
})
|
||||
);
|
||||
|
||||
document.querySelectorAll('.end-move').forEach(el => el.addEventListener('click', () => {
|
||||
recordSheet.endMove();
|
||||
gameboard.endMove();
|
||||
|
||||
13
src/map.js
13
src/map.js
@@ -4,16 +4,23 @@ const svg = document.querySelector('svg');
|
||||
const gb = svg.querySelector('.gameboard');
|
||||
const bg = svg.querySelector('#background');
|
||||
const imageMaps = svg.querySelector('#image-maps');
|
||||
|
||||
const grid = gb.querySelector('.grid');
|
||||
|
||||
if ('cols' in dataset && 'rows' in dataset) {
|
||||
const cellTemplate = svg.querySelector('#hex');
|
||||
const grid = gb.querySelector('.grid');
|
||||
|
||||
createCells(grid, dataset, cellTemplate.id);
|
||||
}
|
||||
|
||||
setElAttrs(bg, calcComputedBboxFor(imageMaps));
|
||||
const sequence = getComputedStyle(gb).transform.match(/-?\d+\.?\d*/g);
|
||||
const mtx = new DOMMatrix(sequence || '');
|
||||
bg.style.transform = mtx;
|
||||
|
||||
const bbox = grid.getBBox();
|
||||
|
||||
bbox.height += 5;
|
||||
|
||||
setElAttrs(bg, bbox);
|
||||
svg.setAttribute('viewBox', formatForViewBox(calcComputedBboxFor(gb)));
|
||||
|
||||
function setElAttrs(el, attrs) {
|
||||
|
||||
@@ -13,8 +13,8 @@ const horzToVertDistRatio = 2 * Math.sqrt(3) / 3,
|
||||
},
|
||||
|
||||
firingArcVisibility = {
|
||||
davion: false,
|
||||
liao: false
|
||||
defender: false,
|
||||
attacker: false
|
||||
},
|
||||
|
||||
clippedFiringArcRadius = 25;
|
||||
|
||||
@@ -29,6 +29,10 @@ function getCounterAndClones(svg, counter) {
|
||||
return svg.querySelectorAll(`.counter${dataSelector(counter)}`);
|
||||
}
|
||||
|
||||
export function getAllCounters(container) {
|
||||
return container.querySelectorAll('g.counter[data-allegiance][data-number]');
|
||||
}
|
||||
|
||||
export function getCounter(svg, selected) {
|
||||
return svg.querySelector(`.counter${dataSelector(selected)}:not(.clone)`);
|
||||
}
|
||||
|
||||
@@ -2,6 +2,10 @@ import * as firingArc from './game/firing_arc.js';
|
||||
import * as sightLine from './game/sight_line.js';
|
||||
import * as soldier from './game/soldier.js';
|
||||
|
||||
let svg, distanceCallback, proneFlagCallback, selectCallback,
|
||||
selected,
|
||||
placing = [];
|
||||
|
||||
function getCellContents(cell) {
|
||||
return cell.querySelectorAll('*:not(use[href="#hex"])');
|
||||
}
|
||||
@@ -26,8 +30,8 @@ function getLockedSightLine(svg) {
|
||||
return svg.querySelector('line.sight-line:not(.active)');
|
||||
}
|
||||
|
||||
export function getSightLine(svg) {
|
||||
return svg.querySelector('line.sight-line');
|
||||
function getSightLine() {
|
||||
return sightLine.getSightLine();
|
||||
}
|
||||
|
||||
function getActiveSightLine(svg) {
|
||||
@@ -109,8 +113,9 @@ function drawSightLine(sourceCell, targetCell) {
|
||||
distanceCallback && distanceCallback(hexes.length - 1);
|
||||
}
|
||||
|
||||
let svg, distanceCallback, proneFlagCallback, selectCallback,
|
||||
placing = [];
|
||||
export function getUnits() {
|
||||
return soldier.getAllCounters(svg);
|
||||
}
|
||||
|
||||
export function setDistanceCallback(callback) {
|
||||
distanceCallback = callback;
|
||||
@@ -143,13 +148,7 @@ export function start(el) {
|
||||
} else if (toPlace && !state.occupant) {
|
||||
soldier.place(svg, toPlace, cell);
|
||||
placing.push(toPlace);
|
||||
const lockedSl = getLockedSightLine(svg);
|
||||
|
||||
if (!lockedSl) {
|
||||
clearSightLine();
|
||||
} else {
|
||||
updateSightLine(cell);
|
||||
}
|
||||
getLockedSightLine(svg) ? updateSightLine(cell) : clearSightLine();
|
||||
} else if (toPlace && state.occupant) {
|
||||
if (toPlace === state.occupant) {
|
||||
if ('previous' in toPlace.dataset) {
|
||||
@@ -187,13 +186,7 @@ export function start(el) {
|
||||
toPlace = state.occupant;
|
||||
soldier.removeClones(svg, toPlace);
|
||||
soldier.getTrace(svg, toPlace).remove();
|
||||
const lockedSl = getLockedSightLine(svg);
|
||||
|
||||
if (!lockedSl) {
|
||||
clearSightLine();
|
||||
} else {
|
||||
updateSightLine(cell);
|
||||
}
|
||||
getLockedSightLine(svg) ? updateSightLine(cell) : clearSightLine();
|
||||
} else {
|
||||
const index = getGridIndex(state.occupant),
|
||||
trace = soldier.getTrace(svg, toPlace),
|
||||
@@ -242,10 +235,15 @@ export function start(el) {
|
||||
});
|
||||
|
||||
cell.addEventListener('pointerover', () => {
|
||||
// should we draw a sight line?
|
||||
// conditions:
|
||||
// we have a soldier selected
|
||||
// that soldier's counter is on the board
|
||||
// the sight line is not locked
|
||||
let selected = getSelected();
|
||||
|
||||
if (selected) {
|
||||
let sl = getSightLine(svg),
|
||||
let sl = getSightLine(),
|
||||
isOnBoard = selected.parentElement.hasAttribute('data-x'),
|
||||
sourceCell = selected.parentElement;
|
||||
|
||||
|
||||
@@ -1,3 +1,51 @@
|
||||
function createIcon(number) {
|
||||
const svgns = 'http://www.w3.org/2000/svg';
|
||||
const [icon, circle, text] = ['svg', 'circle', 'text'].map(t => document.createElementNS(svgns, t));
|
||||
|
||||
icon.setAttributeNS(null, 'viewBox', '-5 -5 10 10')
|
||||
icon.setAttribute('xmlns', svgns);
|
||||
|
||||
circle.setAttributeNS(null, 'cx', 0);
|
||||
circle.setAttributeNS(null, 'cy', 0);
|
||||
circle.setAttributeNS(null, 'r', 5);
|
||||
|
||||
text.textContent = number;
|
||||
|
||||
icon.appendChild(circle);
|
||||
icon.appendChild(text);
|
||||
|
||||
return icon;
|
||||
}
|
||||
|
||||
function createRecord({ dataset: { allegiance, number }}) {
|
||||
const div = document.createElement('div', { is: 'soldier-record-block' }),
|
||||
spans = Array(5).fill('span').map(t => document.createElement(t)),
|
||||
[tn, pwt, pwd, pwrs, pwrl] = spans;
|
||||
|
||||
div.setAttribute('class', 'soldier-record');
|
||||
div.dataset.number = number;
|
||||
div.dataset.allegiance = allegiance;
|
||||
|
||||
tn.setAttribute('slot', 'troop-number');
|
||||
tn.appendChild(createIcon(number));
|
||||
|
||||
pwt.setAttribute('slot', 'primary-weapon-type');
|
||||
pwt.textContent = 'Rifle';
|
||||
|
||||
pwd.setAttribute('slot', 'primary-weapon-damage');
|
||||
pwd.textContent = '4L';
|
||||
|
||||
pwrs.setAttribute('slot', 'primary-weapon-range-short');
|
||||
pwrs.textContent = '1-27';
|
||||
|
||||
pwrl.setAttribute('slot', 'primary-weapon-range-long');
|
||||
pwrl.textContent = '28-75';
|
||||
|
||||
spans.forEach(el => div.appendChild(el));
|
||||
|
||||
return div;
|
||||
}
|
||||
|
||||
export function unSelect() {
|
||||
const selected = getSelected();
|
||||
|
||||
@@ -30,3 +78,22 @@ export function endMove() {
|
||||
|
||||
unSelect();
|
||||
}
|
||||
|
||||
export function createRecords(units, { content }) {
|
||||
const grouped = Array.from(units).reduce((acc, unit) => {
|
||||
acc[unit.dataset.allegiance]?.push(unit) || (acc[unit.dataset.allegiance] = [unit]);
|
||||
return acc;
|
||||
}, {});
|
||||
|
||||
for (const al in grouped) {
|
||||
grouped[al] = grouped[al].map(createRecord);
|
||||
}
|
||||
|
||||
return grouped;
|
||||
}
|
||||
|
||||
export function clear() {
|
||||
document.querySelectorAll('#attacker-record > div, #defender-record > div').forEach(el => el.remove());
|
||||
document.querySelector('#attacker-record .name').textContent = 'attacker';
|
||||
document.querySelector('#defender-record .name').textContent = 'defender';
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user