Web Dev Solutions

Catalin Mititiuc

aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--public/assets/css/map.css122
-rw-r--r--public/assets/css/style.css15
-rw-r--r--public/assets/images/counter_1st_floor.pngbin0 -> 8593 bytes
-rw-r--r--public/assets/images/counter_2nd_floor.pngbin0 -> 7961 bytes
-rw-r--r--public/assets/images/counter_3rd_floor.pngbin0 -> 8250 bytes
-rw-r--r--public/assets/images/counter_basement.pngbin0 -> 7876 bytes
-rw-r--r--public/assets/images/counter_grenade.pngbin0 -> 14868 bytes
-rw-r--r--public/assets/images/counter_prone.pngbin0 -> 6761 bytes
-rw-r--r--public/assets/images/scenario_template.svg16
-rw-r--r--public/index.html19
-rw-r--r--src/index.js5
-rw-r--r--src/modules/game/soldier.js12
-rw-r--r--src/modules/gameboard.js231
13 files changed, 236 insertions, 184 deletions
diff --git a/public/assets/css/map.css b/public/assets/css/map.css
index cd7ea6a..e6a25aa 100644
--- a/public/assets/css/map.css
+++ b/public/assets/css/map.css
@@ -82,10 +82,6 @@ g.troop-counter-template text {
transform: translate(-5px, 6px);
}
-[href="#counter-grenade"] {
- transform: translate(-5px, -5px);
-}
-
g.clone {
stroke: white;
stroke-width: 0.5px;
@@ -173,10 +169,35 @@ polygon.firing-arc[data-allegiance="attacker"] {
stroke-opacity: inherit;
}
-g.counter use {
+/*g.counter use {*/
+/* r: 5px;*/
+/*}*/
+
+g.counter {
r: 5px;
}
+[data-q][data-r][data-s][data-t]:hover g.counter {
+ /*transform: scale(3);*/
+}
+
+g.counter:hover {
+ /*transform: scale(3);*/
+ /*r: 20px;*/
+}
+
+/*g.counter:hover * {*/
+/* r: 20px;*/
+/*}*/
+
+g.counter.selected {
+ r: 6px;
+}
+
+g.counter use.primary-weapon {
+ r: inherit;
+}
+
g.counter use.troop-number, g.counter use.squad-number {
--scale: 0.25;
}
@@ -197,7 +218,8 @@ g.selected use.primary-weapon {
animation: 1s selected 0.25s linear infinite;
stroke-width: 2px;
stroke: yellow;
- r: 6px;
+ /*r: 6px;*/
+ r: inherit;
}
pattern use {
@@ -247,23 +269,42 @@ g[data-y]:nth-child(odd) {
fill: orange;
stroke: black;
}
-
-[data-x]:hover g.counter,
-[data-q][data-r][data-s][data-t]:hover g.counter {
- transform: scale(1.5);
-}
-
-[data-x]:hover g.counter .troop-number,
-[data-q][data-r][data-s][data-t]:hover g.counter .troop-number {
- --translateX: -5px;
- --scale: 0.5;
-}
-
-[data-x]:hover g.counter .squad-number,
-[data-q][data-r][data-s][data-t]:hover g.counter .squad-number {
- --translateX: 5px;
- --scale: 0.5;
-}
+/**/
+/*[data-q][data-r][data-s][data-t] g.counter,*/
+/*[data-q][data-r][data-s][data-t] g.counter .troop-number,*/
+/*[data-q][data-r][data-s][data-t] g.counter .squad-number {*/
+/* transition: transform 0.25s;*/
+/*}*/
+
+/*[data-q][data-r][data-s][data-t]:hover g.counter {*/
+/* transform: scale(2);*/
+/*}*/
+
+/*[data-q][data-r][data-s][data-t]:hover use[href="#hex"] {*/
+/* scale: 0.5;*/
+/*}*/
+
+
+
+/*[data-x]:hover g.counter,*/
+/*[data-q][data-r][data-s][data-t]:hover g.counter {*/
+/* transform: scale(1.5);*/
+/* transition: transform 0.25s;*/
+/*}*/
+/**/
+/*[data-x]:hover g.counter .troop-number,*/
+/*[data-q][data-r][data-s][data-t]:hover g.counter .troop-number {*/
+/* --translateX: -5px;*/
+/* --scale: 0.5;*/
+/* transition: transform 0.25s;*/
+/*}*/
+/**/
+/*[data-x]:hover g.counter .squad-number,*/
+/*[data-q][data-r][data-s][data-t]:hover g.counter .squad-number {*/
+/* --translateX: 5px;*/
+/* --scale: 0.5;*/
+/* transition: transform 0.25s;*/
+/*}*/
[data-x] {
--scale: 1;
@@ -462,10 +503,43 @@ text.elevation {
[data-q][data-r][data-s][data-t] .radial-icon {
cx: calc(var(--cx) / 20);
- cy: calc(var(--cy) / 20)
+ cy: calc(var(--cy) / 20);
}
[data-q][data-r][data-s][data-t]:hover .radial-icon {
cx: var(--cx);
cy: var(--cy);
}
+
+use[class^="counter-"] {
+ --scale: 1;
+ --translateX: -5px;
+ --translateY: -5px;
+ transform: scale(var(--scale)) translate(var(--translateX), var(--translateY));
+ /*transform: translate(var(--translateX), var(--translateY)) scale(var(--scale));*/
+}
+
+use[class^="counter-"] {
+ transition: x 0.25s, y 0.25s;
+ --scale: 0.5;
+ /*--translateY: 0px;*/
+}
+
+.counter use[href^="#counter"] {
+ /*transform: scale(0.5);*/
+}
+
+g.counter use[class^="counter-"] {
+ x: calc(var(--x) * 1.25);
+ y: calc(var(--y) * 1.25);
+ /*y: 10px;*/
+ /*x: var(--x);*/
+ /*y: var(--y);*/
+}
+
+[data-q][data-r][data-s][data-t]:hover use[class^="counter-"],
+ x: calc(var(--x) * 1.5);
+ y: calc(var(--y) * 1.5);
+ /*--scale: 1;*/
+ --translateY: -5px;
+}
diff --git a/public/assets/css/style.css b/public/assets/css/style.css
index e1257a4..af9dd2a 100644
--- a/public/assets/css/style.css
+++ b/public/assets/css/style.css
@@ -576,6 +576,21 @@ div#status {
pointer-events: none;
}
+.counters-list {
+ user-select: none;
+}
+
+.counters-list > img {
+ vertical-align: middle;
+ height: 20px;
+ border: 1px solid lightgray;
+ border-radius: 2px;
+}
+
+.counters-list > img:hover {
+ border: 1px solid gray;
+}
+
@keyframes roll-out {
0% {
transform: scaleX(1);
diff --git a/public/assets/images/counter_1st_floor.png b/public/assets/images/counter_1st_floor.png
new file mode 100644
index 0000000..0728ac0
--- /dev/null
+++ b/public/assets/images/counter_1st_floor.png
Binary files differ
diff --git a/public/assets/images/counter_2nd_floor.png b/public/assets/images/counter_2nd_floor.png
new file mode 100644
index 0000000..8417461
--- /dev/null
+++ b/public/assets/images/counter_2nd_floor.png
Binary files differ
diff --git a/public/assets/images/counter_3rd_floor.png b/public/assets/images/counter_3rd_floor.png
new file mode 100644
index 0000000..82a54a0
--- /dev/null
+++ b/public/assets/images/counter_3rd_floor.png
Binary files differ
diff --git a/public/assets/images/counter_basement.png b/public/assets/images/counter_basement.png
new file mode 100644
index 0000000..05a5be2
--- /dev/null
+++ b/public/assets/images/counter_basement.png
Binary files differ
diff --git a/public/assets/images/counter_grenade.png b/public/assets/images/counter_grenade.png
new file mode 100644
index 0000000..de6112e
--- /dev/null
+++ b/public/assets/images/counter_grenade.png
Binary files differ
diff --git a/public/assets/images/counter_prone.png b/public/assets/images/counter_prone.png
new file mode 100644
index 0000000..4bdaa51
--- /dev/null
+++ b/public/assets/images/counter_prone.png
Binary files differ
diff --git a/public/assets/images/scenario_template.svg b/public/assets/images/scenario_template.svg
index 5480a8c..964e80f 100644
--- a/public/assets/images/scenario_template.svg
+++ b/public/assets/images/scenario_template.svg
@@ -3,13 +3,6 @@
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="../css/radial.css" type="text/css" />
<link xmlns="http://www.w3.org/1999/xhtml" rel="stylesheet" href="../css/map.css" type="text/css" />
- <!--<style>-->
- <!-- .grid .building use {-->
- <!-- opacity: 1;-->
- <!-- fill: teal;-->
- <!-- }-->
- <!--</style>-->
-
<defs>
<polygon id="hex" points="0,10 8.66,5 8.66,-5 0,-10 -8.66,-5 -8.66,5"/>
@@ -33,8 +26,12 @@
<use x="8.66" y="15" transform="rotate(60 8.66 15)" href="#ast-line"/>
</pattern>
- <image id="counter-prone" href="counter_prone.jpg" width="10"/>
- <image id="counter-grenade" href="counter_grenade.jpg" width="10"/>
+ <image id="counter-grenade" href="counter_grenade.png" width="10"/>
+ <image id="counter-prone" href="counter_prone.png" width="10"/>
+ <image id="counter-basement" href="counter_basement.png" width="10"/>
+ <image id="counter-1st-floor" href="counter_1st_floor.png" width="10"/>
+ <image id="counter-2nd-floor" href="counter_2nd_floor.png" width="10"/>
+ <image id="counter-3rd-floor" href="counter_3rd_floor.png" width="10"/>
</defs>
<g class="gameboard" data-view-elevation="0">
@@ -48,5 +45,6 @@
</g>
<g class="grid"/>
+ <g class="pieces"/>
</g>
</svg>
diff --git a/public/index.html b/public/index.html
index f4b28a9..dcaad12 100644
--- a/public/index.html
+++ b/public/index.html
@@ -231,11 +231,24 @@
<button type="button" class="set-firing-arc" data-size="large">
<img src="assets/images/firing_arc_large.png" height="12" /> 6 MP
</button>
- <button type="button" class="set-grenade">
+ <button type="button" class="set-mech-template">Mech</button>
+ </span>
+ <div class="counters-list">
+ <!--<img src="assets/images/counter_grenade.png" />-->
+ <!--<img src="assets/images/counter_prone.png" />-->
+ <!--<img src="assets/images/counter_basement.png" />-->
+ <!--<img src="assets/images/counter_1st_floor.png" />-->
+ <!--<img src="assets/images/counter_2nd_floor.png" />-->
+ <!--<img src="assets/images/counter_3rd_floor.png" />-->
+ <button type="button" class="grenade">
<img src="assets/images/icon_grenade.png" height="12" />
</button>
- <button type="button" class="set-mech-template">M</button>
- </span>
+ <button type="button" class="prone">Prone</button>
+ <button type="button" class="basement">Bsmnt</button>
+ <button type="button" class="1st-floor">1st Flr</button>
+ <button type="button" class="2nd-floor">2nd Flr</button>
+ <button type="button" class="3rd-floor">3rd Flr</button>
+ </div>
</div>
<div id="record-sheet">
diff --git a/src/index.js b/src/index.js
index 46f39fd..d2c1b01 100644
--- a/src/index.js
+++ b/src/index.js
@@ -158,7 +158,10 @@ document.querySelectorAll('.set-firing-arc').forEach(el =>
el.addEventListener('click', gameboard.setFiringArc)
);
-document.querySelector('.set-grenade').addEventListener('click', gameboard.setGrenade);
+document.querySelectorAll('.counters-list button').forEach(el => {
+ el.addEventListener('click', e => gameboard.setCounter(el.className));
+});
+
document.querySelector('.set-mech-template').addEventListener('click', gameboard.setMechTemplate);
document.querySelectorAll('#toggle-firing-arc-vis input').forEach(el =>
diff --git a/src/modules/game/soldier.js b/src/modules/game/soldier.js
index 3ac7b37..a024f9f 100644
--- a/src/modules/game/soldier.js
+++ b/src/modules/game/soldier.js
@@ -108,6 +108,18 @@ export function getTrace(svg, counter) {
}
export function place(svg, selected, cell) {
+ //console.log(selected.parentElement);
+ //const piecesContainer = svg.querySelector('.pieces');
+ //const parent = selected.parentElement;
+ //if (parent)
+ // parent.setAttributeNS(null, 'transform', cell.getAttributeNS(null, 'transform'));
+ //else {
+ // const container = document.createElementNS(svgns, 'g');
+ // container.setAttributeNS(null, 'transform', cell.getAttributeNS(null, 'transform'));
+ // container.append(selected);
+ // piecesContainer.append(container);
+ //}
+
if (svg.querySelector('.grid').contains(selected)) {
const clone = addMoveToHistory(selected);
updatePlacement(cell, selected, clone)
diff --git a/src/modules/gameboard.js b/src/modules/gameboard.js
index ae03364..0c33f05 100644
--- a/src/modules/gameboard.js
+++ b/src/modules/gameboard.js
@@ -196,12 +196,25 @@ function endMove() {
}
}
+function returnPieces(collection) {
+ [...svg.querySelector('.pieces').children].forEach(piece => {
+ collection.get(piece).parent.append(piece);
+ collection.delete(piece);
+ });
+}
+
export function start(el) {
svg = el;
const startingLocations = svg.querySelector('.start-locations');
startingLocations && getUnits(startingLocations).forEach(unit => unit.addEventListener('click', selectOffBoard));
+
+ const pieces = svg.querySelector('.pieces');
+ const inFront = new Map();
+ let inFrontParent;
+ //addEventListener('pointerout', e => { returnPieces(inFront) });
+
getCells(svg).forEach(cell => {
cell.addEventListener('click', e => {
const occupant = getCellOccupant(cell);
@@ -269,6 +282,12 @@ export function start(el) {
});
cell.addEventListener('pointerover', () => {
+ if (!pieces.contains(cell)) {
+ returnPieces(inFront);
+ inFront.set(cell, { parent: cell.parentElement });
+ pieces.append(cell);
+ }
+
const selected = getSelected();
if (placing[0]?.getAttributeNS(null, 'class') == 'mech-template') {
@@ -288,6 +307,22 @@ export function start(el) {
});
cell.addEventListener('pointerout', () => {
+ //if (inFront && inFrontParent) {
+ // inFrontParent.append(inFront);
+ // inFront = null;
+ // inFrontParent = null;
+ //}
+
+ //for (const [el, parent] of inFront) {
+ // parent.append(el);
+ // inFront.delete(el);
+ //}
+ //[...pieces.children].forEach(piece => {
+ // inFront.get(piece).parent.append(piece);
+ // inFront.delete(piece);
+ //});
+ //returnPieces(inFront);
+
getActiveSightLine(svg) && clearSightLine();
const occupant = getCellOccupant(cell);
@@ -299,156 +334,27 @@ export function start(el) {
});
// debug //
- // const attacker = { dataset: { allegiance: 'attacker', number: 1, squad: 1 }};
+ const attacker = { dataset: { allegiance: 'attacker', number: 1, squad: 1 }};
// const defender = { dataset: { allegiance: 'defender', number: 1, squad: 2 }};
- // soldier.place(svg, soldier.createCounter(attacker, 'blazer'), getCell(0, 0, 0, 0));
- // soldier.place(svg, soldier.createCounter(defender, 'rifle'), getCell(-1, 0, 1, 0));
-
- const svgns = "http://www.w3.org/2000/svg";
- const img = document.createElementNS(svgns, 'image');
- img.setAttribute('href', '/assets/images/mech_template.png');
- img.setAttribute('width', '77');
- img.setAttribute('height', '77');
- img.setAttribute('transform', 'translate(-38.75, -38.5)');
- img.style.opacity = 0.2;
- img.style.pointerEvents = 'none';
-
- const mech = document.createElementNS(svgns, 'g');
- mech.setAttribute('transform', 'rotate(0) translate(-2.25, 0)');
- mech.style.pointerEvents = 'none';
-
- const deadZone = document.createElementNS(svgns, 'circle');
- deadZone.style.stroke = 'red';
- deadZone.style.strokeOpacity = 0.5;
- deadZone.style.pointerEvents = 'none';
- deadZone.setAttribute('r', '36.5');
-
- const leftFoot = document.createElementNS(svgns, 'rect');
- leftFoot.style.fill = 'red';
- leftFoot.style.fillOpacity = 0.5;
- leftFoot.setAttribute('x', '-16.25');
- leftFoot.setAttribute('y', '5.75');
- leftFoot.setAttribute('width', '34.5');
- leftFoot.setAttribute('height', '12.25');
-
- const rightFoot = document.createElementNS(svgns, 'rect');
- rightFoot.style.fill = 'red';
- rightFoot.style.fillOpacity = 0.5;
- rightFoot.setAttribute('x', '-16.25');
- rightFoot.setAttribute('y', '5.75');
- rightFoot.setAttribute('width', '34.5');
- rightFoot.setAttribute('height', '12.25');
- rightFoot.setAttribute('transform', 'scale(1 -1)');
-
- const forwardArc = document.createElementNS(svgns, 'path');
- forwardArc.setAttribute('d', 'M -4,0 L -32.55,-16.5 A 36.5 36.5 0 0 0 -32.55,16.5 Z');
-
- const rearArc = document.createElementNS(svgns, 'path');
- rearArc.setAttribute('d', 'M 4,0 L 32.55,-16.5 A 36.5 36.5 0 0 1 32.55,16.5 Z');
-
- const forwardRightArc = document.createElementNS(svgns, 'path');
- forwardRightArc.setAttribute('d', 'M 0,2.3 L -32.55,-16.5 A 36.5 36.5 0 0 1 0,-36.5 Z');
-
- const forwardLeftArc = document.createElementNS(svgns, 'path');
- forwardLeftArc.setAttribute('d', 'M 0,-2.3 L -32.55,16.5 A 36.5 36.5 0 0 0 0,36.5 Z');
-
- const rightArc = document.createElementNS(svgns, 'path');
- rightArc.setAttribute('d', 'M 0,2.3 L 32.55,-16.5 A 36.5 36.5 0 0 0 0,-36.5 Z');
-
- const leftArc = document.createElementNS(svgns, 'path');
- leftArc.setAttribute('d', 'M 0,-2.3 L 32.55,16.5 A 36.5 36.5 0 0 1 0,36.5 Z');
-
- const arcs = document.createElementNS(svgns, 'g');
- arcs.setAttribute('mask', 'url(#mech-template-mask)');
- arcs.style.stroke = 'white';
- arcs.style.strokeOpacity = 0.5;
-
- const mask = document.createElementNS(svgns, 'mask');
- mask.id = 'mech-template-mask';
-
- const visible = document.createElementNS(svgns, 'circle');
- visible.setAttribute('fill', 'white');
- visible.setAttribute('r', '36.5');
-
- const invisible = document.createElementNS(svgns, 'rect');
- invisible.setAttribute('x', '-16.25');
- invisible.setAttribute('y', '-18');
- invisible.setAttribute('width', '34.5');
- invisible.setAttribute('height', '36');
- invisible.setAttribute('fill', 'black');
-
- const arrow = document.createElementNS(svgns, 'polyline');
- arrow.setAttribute('points', '-23,-3 -25,0 -23,3');
- arrow.style.stroke = 'black';
-
- mask.append(visible);
- mask.append(invisible);
-
- mech.append(img);
- mech.append(deadZone);
- mech.append(leftFoot);
- mech.append(rightFoot);
- mech.append(arrow);
- arcs.append(forwardArc);
- arcs.append(rearArc);
- arcs.append(forwardRightArc);
- arcs.append(forwardLeftArc);
- arcs.append(rightArc);
- arcs.append(leftArc);
- mech.append(arcs);
-
const cell = getCell(2, 0, -2, 0);
-
- //cell.append(mask);
- //cell.append(mech);
-
- const icons = Array(4).fill(null);
- const length = 10;
-
- const gravity = 1;
- const lateralForce = gravity;
- const rads = Math.atan(lateralForce / gravity);
- const mult = icons.length % 2 ? index => Math.ceil(index / 2) : index => Math.floor(index / 2) + 0.5;
- const iconBestFitCount = 8;
- const divider = icons.length > iconBestFitCount ? iconBestFitCount / icons.length : 1;
-
- function getRandomIntInclusive(min, max) {
- const minCeiled = Math.ceil(min);
- const maxFloored = Math.floor(max);
- return Math.floor(Math.random() * (maxFloored - minCeiled + 1) + minCeiled); // The maximum is inclusive and the minimum is inclusive
- }
-
- icons.forEach((color, index) => {
- const theta = rads * (index % 2 ? -1 : 1) * mult(index) * divider;
- const cx = length * Math.sin(theta);
- const cy = length * Math.cos(theta);
-
- const randomColor = `rgb(${getRandomIntInclusive(0, 200)}, ${getRandomIntInclusive(0, 200)}, ${getRandomIntInclusive(0, 200)})`;
- const pt = document.createElementNS(svgns, 'circle');
- pt.classList.add('radial-icon');
- pt.setAttributeNS(null, 'r', 3);
- pt.setAttributeNS(null, 'fill', randomColor);
- //pt.setAttributeNS(null, 'fill-opacity', 0.5);
- pt.setAttributeNS(null, 'style', `--cx: ${cx}px; --cy: ${cy}px`);
- //pt.style.cx = `--cx: ${cx}px`;
- //pt.style.cy = `--cy: ${cy}px`;
- //pt.setAttributeNS(null, 'cx', cx);
- //pt.setAttributeNS(null, 'cy', cy);
-
- cell.append(pt);
- });
-
- //const mechTemplate = document.createElementNS(svgns, 'use');
- //mechTemplate.setAttributeNS(null, 'href', '#fallen-mech-template');
- //mechTemplate.setAttribute('href', '#standing-mech-template');
- //mechTemplate.setAttributeNS(null, 'href', '#vehicle-template');
- //cell.append(mechTemplate);
- console.log(cell);
+ const trooper = soldier.createCounter(attacker, 'blazer');
+ soldier.place(svg, trooper, cell);
///////////
Observable.subscribe('select', select);
Observable.subscribe('endmove', endMove);
+
+ Observable.notify('select', trooper);
+
+ //Array(1).fill(null).forEach(() => {
+ // const counter = document.createElementNS(svgns, 'use');
+ // counter.setAttributeNS(null, 'href', '#counter-grenade');
+ // counter.classList.add('counter-grenade');
+ // trooper.appendChild(counter);
+ //});
+ //
+ //setGrenade();
console.log('gameboard.js loaded');
}
@@ -483,11 +389,42 @@ export function setFiringArc() {
}
}
-export function setGrenade() {
- let counter = document.createElementNS(svgns, 'use');
- counter.setAttributeNS(null, 'href', '#counter-grenade');
+export function setCounter(name) {
+ const selected = getSelected();
- placing.push(counter);
+ const counter = document.createElementNS(svgns, 'use');
+ counter.addEventListener('click', e => {
+ e.stopPropagation()
+ counter.remove()
+ });
+ //counter.setAttributeNS(null, 'href', '#counter-grenade');
+ counter.setAttributeNS(null, 'href', `#counter-${name}`);
+ counter.classList.add(`counter-${name}`);
+
+ if (selected) {
+ const icons = [...selected.querySelectorAll('use[class^="counter-"]'), counter];
+ const length = 12;
+ const gravity = 1;
+ const lateralForce = gravity;
+ const rads = Math.atan(lateralForce / gravity);
+ const mult = icons.length % 2 ? index => Math.ceil(index / 2) : index => Math.floor(index / 2) + 0.5;
+ const iconBestFitCount = 8;
+ const divider = icons.length > iconBestFitCount ? iconBestFitCount / icons.length : 1;
+
+ icons
+ .map((icon, index) => [icon, (index % 2 ? -1 : 1) * mult(index)])
+ .sort(([_ic1, i1], [_ic2, i2]) => i1 < i2)
+ .forEach(([icon, index]) => {
+ const theta = rads * index * divider;
+ const x = length * Math.sin(theta);
+ const y = length * Math.cos(theta);
+ icon.setAttributeNS(null, 'style', `--x: ${x}px; --y: ${y}px`);
+ //selected.appendChild(icon);
+ if (!selected.contains(icon)) selected.append(icon);
+ });
+ }
+ else
+ placing.push(counter);
}
function handleMechTemplateRotation(event) {