index : btroops | |
Virtual board game-aid for BattleTroops, an infantry combat simulator wargame published by FASA in 1989. |
aboutsummaryrefslogtreecommitdiff |
diff options
-rw-r--r-- | index.html | 83 | ||||
-rw-r--r-- | index.js | 107 | ||||
-rw-r--r-- | style.css | 69 |
3 files changed, 179 insertions, 80 deletions
@@ -5,7 +5,7 @@ <link rel="stylesheet" href="style.css"> </head> <body> - <svg viewbox="-100 -100 3450 2400" xmlns="http://www.w3.org/2000/svg" stroke-width="20"> + <svg viewbox="-100 -100 3450 2400" xmlns="http://www.w3.org/2000/svg"> <defs> <pattern id="inch-mark" x="0" y="0" width="2in" height="2in" patternUnits="userSpaceOnUse"> <rect x="0" y="0" width="1in" height="2in" fill="black" /> @@ -21,28 +21,30 @@ <!-- <circle id="point" cx="0" cy="0" r="0.07in" /> --> <circle id="point" cx="0" cy="0" r="0.5in" /> - <polygon id="hex" fill="url('#gradient')" points="0,121.32 184.152,15.544 368.312,121.32 368.312,332.864 184.152,438.64 0,332.864 "/> + <polygon id="hex" points="0,121.32 184.152,15.544 368.312,121.32 368.312,332.864 184.152,438.64 0,332.864 "/> <text id="asterisk" x="-0.06in" y="0.22in">*</text> </defs> - - <line x1="0" y1="-0.25in" x2="34in" y2="-0.25in" stroke="url(#inch-mark)" /> - <line x1="-0.25in" y1="0" x2="-0.25in" y2="23in" stroke="url(#vert)" /> + + <line class="ruler" x1="0" y1="-0.25in" x2="34in" y2="-0.25in" stroke="url(#inch-mark)" /> + <line class="ruler" x1="-0.25in" y1="0" x2="-0.25in" y2="23in" stroke="url(#vert)" /> <!-- <image id="img1" href="map1.png" height="6.428in" width="9.971in" /> --> <image id="img2" href="scans/map1.jpg" width="2284" height="1518" /> <g id="firing-arcs"></g> <rect id="map" x="0" y="0" width="34in" height="23in" /> </svg> - Set firing arc: - <button type="button" class="set-firing-arc" data-size="small"> - <img src="firing_arc_small.png" height="12" /> 2 MP - </button> - <button type="button" class="set-firing-arc" data-size="medium"> - <img src="firing_arc_medium.png" height="12" /> 4 MP - </button> - <button type="button" class="set-firing-arc" data-size="large"> - <img src="firing_arc_large.png" height="12" /> 6 MP - </button> + <div> + Set firing arc: + <button type="button" class="set-firing-arc" data-size="small"> + <img src="firing_arc_small.png" height="12" /> 2 MP + </button> + <button type="button" class="set-firing-arc" data-size="medium"> + <img src="firing_arc_medium.png" height="12" /> 4 MP + </button> + <button type="button" class="set-firing-arc" data-size="large"> + <img src="firing_arc_large.png" height="12" /> 6 MP + </button> + </div> <div id="record-sheet"> <div> @@ -53,19 +55,60 @@ 17th Kestral Mechanized Infantry --> </p> <div class="soldier-record" data-troop-number="1" data-troop-allegiance="davion"> - Troop Number: 1<br> - Primary Weapon Type: Rifle, Damage: 4L, Short: 1-27, Long: 28-75<br> - HG: 4 + <!-- <p class="damage"> + <span> + <label> + <input type="checkbox" /> Bruise + </label> + <label> + <input type="checkbox" /> Lethal + </label> + </span> + <span> + <label> + <input type="checkbox" /> + Bruise + </label> + <label> + <input type="checkbox" /> + Lethal + </label> + </span> + </p> --> + <p class="damage"> + <span> + <!-- <label> + </label> + <label> + </label> + <label> + </label> --> + <input type="radio" name="d1"> + <!-- <label>label1</label> --> + <input type="radio" name="d1"> + <!-- <label>label2</label> --> + <input type="radio" name="d1" checked> + <!-- <label>label3</label> --> + </span> + </p> + <p><span>Troop Number</span> 1</p> + <p><span>Primary Weapon Type</span> Rifle</p> + <ul> + <li><span>Damage</span> 4L</li> + <li><span>Short</span> 1-27</li> + <li><span>Long</span> 28-75</li> + </ul> + <p><span>Hand Grenades</span> 4</p> </div> <div class="soldier-record" data-troop-number="2" data-troop-allegiance="davion"> Troop Number: 2<br> Primary Weapon Type: SMG, Damage: 3L, Short: 1-15, Long: 16-25<br> - HG: 4 + Hand Grenades: 4 </div> <div class="soldier-record" data-troop-number="3" data-troop-allegiance="davion"> Troop Number: 3<br> Primary Weapon Type: Blazer, Damage: 4L, Short: 1-17, Long: 18-105<br> - HG: 4 + Hand Grenades: 4 </div> </div> <div> @@ -10,6 +10,21 @@ function radToDeg(radians) { return radians * 180 / Math.PI; } +function calculateAngle(xDiff, yDiff) { + yDiff = -yDiff; + let angle = Math.abs(Math.atan(yDiff / xDiff)); + + if (xDiff < 0 && yDiff > 0) { + angle = Math.PI - angle; + } else if (xDiff < 0 && yDiff < 0) { + angle = Math.PI + angle; + } else if (xDiff > 0 && yDiff < 0) { + angle = 2 * Math.PI - angle; + } + + return angle; +} + function edgePoint(x1, y1, x2, y2, maxX, maxY) { let pointCoords, xDiff = x2 - x1, @@ -100,11 +115,31 @@ POINTS.forEach((row, index) => row.forEach(([x, y]) => { `.counter[data-troop-number="${selectedSoldier.dataset.troopNumber}"][data-troop-allegiance="${selectedSoldier.dataset.troopAllegiance}"]` ).forEach(el => el.remove()); + counter.addEventListener('click', e => { + document.querySelectorAll( + `.counter[data-troop-number="${selectedSoldier.dataset.troopNumber}"][data-troop-allegiance="${selectedSoldier.dataset.troopAllegiance}"]` + ).forEach(el => el.remove()); + + document.querySelectorAll( + `.firing-arc[data-troop-number="${selectedSoldier.dataset.troopNumber}"][data-troop-allegiance="${selectedSoldier.dataset.troopAllegiance}"]` + ).forEach(el => el.remove()); + }); + svg.appendChild(counter); svg.appendChild(text); } }); + point.addEventListener('mouseover', e => { + let selectedSoldier = document.querySelector('.soldier-record.selected'); + + if (selectedSoldier) { + e.target.classList.add('active'); + } + }); + + point.addEventListener('mouseout', e => e.target.removeAttribute('class')); + svg.appendChild(point); })); @@ -129,16 +164,8 @@ map.addEventListener('mousemove', e => { ]; let xDiff = x2px - x1px; - let yDiff = -(y2px - y1px); - let angle = Math.abs(Math.atan(yDiff / xDiff)); - - if (xDiff < 0 && yDiff > 0) { - angle = Math.PI - angle; - } else if (xDiff < 0 && yDiff < 0) { - angle = Math.PI + angle; - } else if (xDiff > 0 && yDiff < 0) { - angle = 2 * Math.PI - angle; - } + let yDiff = y2px - y1px; + let angle = calculateAngle(xDiff, yDiff); console.log('angle:', `${toFixed(radToDeg(angle))}\u00B0`, `${angle}rad`); @@ -167,9 +194,6 @@ map.addEventListener('mousemove', e => { let points; - xDiff = x2px - x1px; - yDiff = y2px - y1px; - if (oppositeEdgeConditions.some(e => e)) { let cornerPoints; @@ -186,7 +210,6 @@ map.addEventListener('mousemove', e => { cornerPoints = [[0, 0], [maxXpx, 0]]; } - // points = `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2} ${cornerPoints[0]} ${cornerPoints[1]}`; } else if (xDiff < 0 && yDiff > 0) { if ((newY1 == 0 && newY2 == maxYpx) || (newY1 == maxYpx && newY2 == 0)) { cornerPoints = [[0, maxYpx], [0, 0]]; @@ -194,7 +217,6 @@ map.addEventListener('mousemove', e => { cornerPoints = [[maxXpx, maxYpx], [0, maxYpx]]; } - // points = `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2} ${cornerPoints[0]} ${cornerPoints[1]}`; } else { if ((newY1 == 0 && newY2 == maxYpx) || (newY1 == maxYpx && newY2 == 0)) { cornerPoints = [[0, maxYpx], [0, 0]]; @@ -202,40 +224,12 @@ map.addEventListener('mousemove', e => { cornerPoints = [[0, 0], [maxXpx, 0]]; } - // points = `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2} ${cornerPoints[0]} ${cornerPoints[1]}`; } points = `${x1px},${y1px} ${newX1},${newY1} ${cornerPoints[1]} ${cornerPoints[0]} ${newX2},${newY2}`; } else if (orthogonalEdgeConditions.some(e => e)) { - let cornerPoint; let cornerPoints = []; - - // console.log('x1px', x1px, 'y1px', y1px, 'x2px', x2px, 'y2px', y2px); - console.log('xDiff', xDiff, 'yDiff', yDiff); - - if (newX1 == 0 || newX1 == maxXpx) { - cornerPoint = [newX1, newY2]; - } else { - cornerPoint = [newX2, newY1]; - } - - if (newX1 == 0 || newX1 == maxXpx) { - console.log(newX1, newY1, 'nearest corner point', newX1, yDiff > 0 ? maxYpx : 0); - } else { - console.log(newX1, newY1, 'nearest corner point', xDiff > 0 ? maxXpx : 0, newY1); - } - - if (newX2 == 0 || newX2 == maxXpx) { - console.log(newX2, newY2, 'nearest corner point', newX2, yDiff > 0 ? maxYpx : 0); - } else { - console.log(newX2, newY2, 'nearest corner point', xDiff > 0 ? maxXpx : 0, newY2); - } - let cp1, cp2; - console.log('x1px, y1px', x1px, y1px); - console.log('newX1, newY1', newX1, newY1); - console.log('newX2, newY2', newX2, newY2); - if (newX1 == 0 || newX1 == maxXpx) { cp1 = [newX1, yDiff > 0 ? maxYpx : 0]; } else { @@ -248,8 +242,6 @@ map.addEventListener('mousemove', e => { cp2 = [xDiff > 0 ? maxXpx : 0, newY2]; } - console.log('cp1', cp1, 'cp2', cp2); - if (cp1[0] == cp2[0] && cp1[1] == cp2[1]) { cornerPoints.push(cp1); } else { @@ -258,13 +250,8 @@ map.addEventListener('mousemove', e => { cornerPoints.push(cp2); } - console.log(`${cornerPoints.join(' ')}`); - - // points = `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2}`; points = `${x1px},${y1px} ${newX1},${newY1} ${cornerPoints.join(' ')} ${newX2},${newY2}`; - console.log('points', points); } else { - points = `${newX1},${newY1} ${x1px},${y1px} ${newX2},${newY2}`; points = `${x1px},${y1px} ${newX1},${newY1} ${newX2},${newY2}`; } @@ -274,13 +261,15 @@ map.addEventListener('mousemove', e => { document.querySelectorAll('.soldier-record').forEach(el => el.addEventListener('click', e => { - if (e.target.classList.contains('selected')) { - e.target.classList.remove('selected'); - } else { - document.querySelectorAll('.soldier-record.selected').forEach(el => - el.classList.remove('selected') - ); - e.target.classList.add('selected'); + if (e.target.tagName !== 'INPUT' && e.target.tagName !== 'LABEL') { + if (el.classList.contains('selected')) { + el.classList.remove('selected'); + } else { + document.querySelectorAll('.soldier-record.selected').forEach(el => + el.classList.remove('selected') + ); + el.classList.add('selected'); + } } }) ); @@ -306,7 +295,7 @@ document.querySelectorAll('.set-firing-arc').forEach(el => el.addEventListener(' let firingArcPlacementListener = e => { document.querySelectorAll('.firing-arc.active').forEach(el => el.classList.remove('active')); - document.querySelector('circle#point').style.pointerEvents = 'auto'; + document.querySelector('circle#point').style.display = ''; map.removeEventListener('click', firingArcPlacementListener); }; @@ -323,7 +312,7 @@ document.querySelectorAll('.set-firing-arc').forEach(el => el.addEventListener(' arcLayer.prepend(firingArc); - document.querySelector('circle#point').style.pointerEvents = 'none'; + document.querySelector('circle#point').style.display = 'none'; } } }));
\ No newline at end of file @@ -8,6 +8,16 @@ body { circle#point { fill: transparent; + stroke: black; + stroke-width: 2px; +} + +use[href="#point"] { + opacity: 0; +} + +use[href="#point"].active { + opacity: 1; } circle.counter[data-troop-allegiance="liao"] { @@ -25,6 +35,8 @@ text.counter { fill: white; stroke-width: 2px; font-family: sans-serif; + cursor: default; + pointer-events: none; } rect#map { @@ -46,6 +58,61 @@ line.firing-arc { opacity: 0.1; } +line.ruler { + stroke-width: 0.25in; +} + +.soldier-record span { + font-size: smaller; + font-family: monospace; + margin-right: 1em; +} + +.soldier-record ul { + margin: 0; + padding: 0; +} + +.soldier-record ul li { + display: inline; + margin-left: 1em; +} + +.soldier-record p { + margin: 0; +} + +.soldier-record p.damage span { + display: inline-block; +} + +.soldier-record p.damage span input { + display: block; +} + +input { + border: none; + outline: 2px solid deeppink; +} + +input:first-of-type { + outline: none; +} + +input:checked { + border: none; + outline: 2px solid deeppink; +} + +input:has(+ input:checked) { + border: none; + outline: 2px solid deeppink; +} + +input[type="radio"]:checked + input { + outline: none; +} + image#img1 { transform: scale(3.41) rotate(-0.15deg); /* opacity: 0.33; */ @@ -84,7 +151,7 @@ image#img2 { padding: 0 2px; } -#record-sheet > div div { +#record-sheet > div > div { border: 1px solid black; margin: 2px 0; padding: 2px; |