From e8a5f5410a0e876d889a2a8137c34bb925f65408 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Fri, 8 Apr 2022 01:29:54 +0200 Subject: Assets. --- play.js | 356 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 356 insertions(+) create mode 100644 play.js (limited to 'play.js') diff --git a/play.js b/play.js new file mode 100644 index 0000000..0c116bf --- /dev/null +++ b/play.js @@ -0,0 +1,356 @@ +"use strict" + +// https://www.redblobgames.com/grids/hexagons/ + +const svgNS = "http://www.w3.org/2000/svg" +const round = Math.round +const sqrt = Math.sqrt + +let ui = { + hexes: [], + sides: [], + hex_x: [], + hex_y: [], + units: [], + onmap: document.getElementById("units"), + focus: null, +} + +function unit_hex(u) { + return view.units[u] >>> 5 +} + +function unit_lost_steps(u) { + return view.units[u] & 3 +} + +function is_unit_supplied(u) { + return (view.units[u] & 4) === 4 +} + +function is_unit_disrupted(u) { + return (view.units[u] & 8) === 8 +} + +function is_unit_moved(u) { + return (view.units[u] & 16) === 16 +} + +function is_unit_action(unit) { + return !!(view.actions && view.actions.unit && view.actions.unit.includes(unit)) +} + +function is_unit_selected(unit) { + return !!(view.selected && view.selected.includes(unit)) +} + +function is_hex_action(hex) { + return !!(view.actions && view.actions.hex && view.actions.hex.includes(hex)) +} + +function is_hex_axis_supply(hex) { + return view.axis_supply[hex] > 0 +} + +function is_side_axis_supply_line(side) { + return view.axis_supply_line[side] > 0 +} + +function is_hex_allied_supply(hex) { + return view.allied_supply[hex] > 0 +} + +function is_side_allied_supply_line(side) { + return view.allied_supply_line[side] > 0 +} + +function focus_stack(stack) { + if (ui.focus !== stack) { + console.log("FOCUS STACK", stack) + ui.focus = stack + update_map() + return stack.length <= 1 + } + return true +} + +function blur_stack() { + if (ui.focus !== null) { + console.log("BLUR STACK") + ui.focus = null + update_map() + } +} + +function on_blur(evt) { + document.getElementById("status").textContent = "" +} + +function on_click_hex(evt) { + if (evt.button === 0) { + send_action('hex', evt.target.hex) + } +} + +function on_click_unit(evt) { + if (evt.button === 0) { + evt.stopPropagation() + if (focus_stack(evt.target.stack)) + send_action('unit', evt.target.unit) + return true + } +} + +document.getElementById("map").addEventListener("mousedown", function (evt) { + if (evt.button === 0) { + blur_stack() + } +}) + +function on_focus_hex(evt) { + let h = evt.target.hex + let text = "(" + h + ") " + hex_name[h] + for (let r in regions) + if (regions[r].includes(h)) + text += " - " + r + document.getElementById("status").textContent = text +} + +function on_focus_unit(evt) { + let u = evt.target.unit + let data = units[u] + document.getElementById("status").textContent = `(${u}) ${data.nationality} ${data.elite ? "elite " : ""}${data.type} - ${data.steps} - ${data.name}` +} + +function toggle_units() { + document.getElementById("units").classList.toggle("hide") +} + +const CLEAR = 2 +const PASS = 1 +const ROUGH = 0 + +const TRAIL = 1 +const TRACK = 2 +const HIGHWAY = 4 + +// visible map width = 22 hexes: el agheila -> alexandria +// visible map height = 9 hexes: oasis to derne + +const map_w = 25 +const map_h = 9 + +let hexnext = [ 1, map_w, map_w-1, -1, -map_w, -(map_w-1) ] + +function build_hexes() { + let yoff = 4 + let xoff = 62 + let hex_w = 121.5 + let hex_r = hex_w / sqrt(3) + let hex_h = hex_r * 2 + + let w = hex_w / 2 + let a = hex_h / 2 + let b = hex_h / 4 + + function add_line(x, y, s, side_id) { + let x1, y1, x2, y2 + switch (s) { + case 0: x1 = (x+w); y1 = (y+b); x2 = (x+w); y2 = (y-b); break; // E + case 1: x1 = (x+0); y1 = (y+a); x2 = (x+w); y2 = (y+b); break; // SE + case 2: x1 = (x-w); y1 = (y+b); x2 = (x+0); y2 = (y+a); break; // SW + case 3: x1 = (x-w); y1 = (y+b); x2 = (x-w); y2 = (y-b); break; // W + case 4: x1 = (x-w); y1 = (y-b); x2 = (x+0); y2 = (y-a); break; // NW + case 5: x1 = (x+0); y1 = (y-a); x2 = (x+w); y2 = (y-b); break; // NE + } + path.push("M", x1, y1, x2, y2) + + let side = ui.sides[side_id] = document.createElementNS(svgNS, "line") + document.getElementById("mapsvg").getElementById("sides").appendChild(side) + + let cn = "side" + if (side_limit[side_id] === 0) cn += " rough" + else if (side_limit[side_id] === 1) cn += " gap" + else if (side_limit[side_id] === 2) cn += " clear" + if (side_road[side_id] === 1) cn += " trail" + else if (side_road[side_id] === 2) cn += " track" + else if (side_road[side_id] === 4) cn += " highway" + + side.setAttribute("class", cn) + side.setAttribute("x1", x1) + side.setAttribute("y1", y1) + side.setAttribute("x2", x2) + side.setAttribute("y2", y2) + side.side = side_id + } + + function add_hex(x, y) { + return [ + [ round(x), round(y-a) ], + [ round(x+w), round(y-b) ], + [ round(x+w), round(y+b) ], + [ round(x), round(y+a) ], + [ round(x-w), round(y+b) ], + [ round(x-w), round(y-b) ] + ].join(" ") + } + + let path = [] + for (let y = 0; y < map_h+1; ++y) { + for (let x = 0; x < map_w+1; ++x) { + let hex_id = y * map_w + x + let xx = x + y/2 - 4.5 + let hex_x = (xoff + hex_w * xx + hex_w/2) + let hex_y = (yoff + hex_h * 3 / 4 * y + hex_h/2) + + ui.hex_x[hex_id] = round(hex_x) + ui.hex_y[hex_id] = round(hex_y) + + // Add hex cell + if (hex_exists[hex_id]) + { + let hex = ui.hexes[hex_id] = document.createElementNS(svgNS, "polygon") + hex.setAttribute("class", "hex") + hex.setAttribute("points", add_hex(hex_x, hex_y)) + hex.addEventListener("mousedown", on_click_hex) + hex.addEventListener("mouseenter", on_focus_hex) + hex.addEventListener("mouseleave", on_blur) + hex.hex = hex_id + document.getElementById("mapsvg").getElementById("hexes").appendChild(hex) + } + + // Add hex sides + // if (hex_exists[hex_id]) + { + for (let s = 0; s < 3; ++s) { + let next_id = hex_id + hexnext[s] + // if (hex_exists[next_id]) + { + let side_id = hex_id * 3 + s + add_line(hex_x, hex_y, s, side_id) + } + } + } + } + } + + for (let month = 1; month <= 20; ++month) { + ui.hex_y[map_w * map_h + month] = 24 + 37 + ui.hex_x[map_w * map_h + month] = 1000 + 37 + (month-1) * 81 + } + + document.getElementById("mapsvg").getElementById("grid").setAttribute("d", path.join(" ")) +} + +function build_units() { + function build_unit(u, data) { + let elt = ui.units[u] = document.createElement("div") + elt.className = `unit ${data.nationality} u${u} r0` + elt.addEventListener("mousedown", on_click_unit) + elt.addEventListener("mouseenter", on_focus_unit) + elt.addEventListener("mouseleave", on_blur) + elt.unit = u + } + for (let u = 0; u < units.length; ++u) { + build_unit(u, units[u]) + } +} + +build_hexes() +build_units() + +let stack = new Array(map_w * map_h + 21) +for (let i = 0; i < stack.length; ++i) + stack[i] = [] + +function update_map() { + for (let i = 0; i < stack.length; ++i) + stack[i].length = 0 + for (let u = 0; u < units.length; ++u) { + let e = ui.units[u] + let hex = unit_hex(u) + if (hex) { + if (!ui.onmap.contains(e)) + ui.onmap.appendChild(e) + stack[hex].push(u) + e.stack = stack[hex] + } else { + e.remove() + } + } + + for (let hex = 0; hex < stack.length; ++hex) { + for (let i = 0; i < stack[hex].length; ++i) { + let u = stack[hex][i] + let e = ui.units[u] + let x, y, z + + if (stack[hex] === ui.focus) { + x = ui.hex_x[hex] - 30 + y = ui.hex_y[hex] - 30 + i * 64 + z = 100 + } else { + if (stack[hex].length <= 4) { + x = ui.hex_x[hex] - 30 + i * 13 + y = ui.hex_y[hex] - 30 + i * 16 + } else if (stack[hex].length <= 8) { + x = ui.hex_x[hex] - 30 + i * 8 + y = ui.hex_y[hex] - 30 + i * 8 + } else { + x = ui.hex_x[hex] - 30 + i * 3 + y = ui.hex_y[hex] - 30 + i * 3 + } + z = 1 + i + } + + e.style.top = y + "px" + e.style.left = x + "px" + e.style.zIndex = z + + let r = unit_lost_steps(u) + e.classList.toggle("r0", r === 0) + e.classList.toggle("r1", r === 1) + e.classList.toggle("r2", r === 2) + e.classList.toggle("r3", r === 3) + + e.classList.toggle("action", is_unit_action(u)) + e.classList.toggle("selected", is_unit_selected(u)) + } + if (ui.hexes[hex]) { + ui.hexes[hex].classList.toggle("action", is_hex_action(hex)) + if (view.axis_supply) { + ui.hexes[hex].classList.toggle("axis_supply", is_hex_axis_supply(hex)) + for (let s = 0; s < 3; ++s) + ui.sides[hex*3+s].classList.toggle("axis_supply", is_side_axis_supply_line(hex*3+s)) + } + if (view.allied_supply) { + ui.hexes[hex].classList.toggle("allied_supply", is_hex_allied_supply(hex)) + for (let s = 0; s < 3; ++s) + ui.sides[hex*3+s].classList.toggle("allied_supply", is_side_allied_supply_line(hex*3+s)) + } + } + } +} + +function on_update() { + update_map() + + action_button("overrun", "Overrun") + action_button("rommel", "Rommel") + action_button("end_move", "End move") + action_button("stop", "Stop") + + action_button("group", "Group") + action_button("regroup", "Regroup") + + action_button("basic", "Basic") + action_button("offensive", "Offensive") + action_button("assault", "Assault") + action_button("blitz", "Blitz") + action_button("pass", "Pass") + + action_button("next", "Next") + action_button("undo", "Undo") +} + +scroll_with_middle_mouse("main") -- cgit v1.2.3