summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-09-02 18:29:50 +0200
committerTor Andersson <tor@ccxvii.net>2022-11-17 13:11:26 +0100
commitda7fb6c52fcb520d3a1a270433e70b607a3fb800 (patch)
tree213a8283fa1de5c32393e2b57f9b18fbcaec9149
parent9d16099a168f0f31100e8293e1509620b099e20c (diff)
downloadrommel-in-the-desert-da7fb6c52fcb520d3a1a270433e70b607a3fb800.tar.gz
Use svg lines to show supply lines.
-rw-r--r--map.svg1
-rw-r--r--play.html39
-rw-r--r--play.js81
-rw-r--r--rules.js108
4 files changed, 157 insertions, 72 deletions
diff --git a/map.svg b/map.svg
index 15b9d4e..30346a4 100644
--- a/map.svg
+++ b/map.svg
@@ -398,5 +398,6 @@
<g id="hexes" fill="transparent" stroke="transparent"></g>
<g id="sides"></g>
+<g id="lines"></g>
</svg>
diff --git a/play.html b/play.html
index f439c31..a7775e8 100644
--- a/play.html
+++ b/play.html
@@ -45,7 +45,7 @@ header.your_turn { background-color: orange; }
display: flex;
flex-wrap: wrap;
justify-content: center;
- min-height: 350px;
+ min-height: 170px;
max-width: 2672px;
gap: 20px;
}
@@ -373,34 +373,31 @@ svg .hex.allied_supply {
fill-opacity: 0.4;
}
-svg .side.axis_supply {
- stroke: darkslategray !important;
- stroke-width: 122px;
- stroke-width: 121.5px;
- stroke-width: 72px;
- stroke-linecap: butt;
- stroke-dasharray: 8 100;
- stroke-dashoffset: -31;
- stroke-opacity: 0.6;
+svg .hex.axis_supply.allied_supply {
+ fill: darkgoldenrod;
+ fill-opacity: 0.4;
+}
+
+svg #lines line {
+ pointer-events: none;
+ stroke: none;
+ stroke-width: 6px;
+ stroke-linecap: round;
}
-svg .side.allied_supply {
- stroke: darkred !important;
- stroke-width: 122px;
- stroke-width: 121.5px;
- stroke-width: 72px;
- stroke-linecap: butt;
- stroke-dasharray: 8 100;
- stroke-dashoffset: -31;
+svg #lines line.axis_supply {
+ stroke: darkslategray;
stroke-opacity: 0.6;
}
-svg .hex.axis_supply.allied_supply {
- fill: orange;
+svg #lines line.allied_supply {
+ stroke: darkred;
+ stroke-opacity: 0.6;
}
-svg .side.allied_supply.axis_supply {
+svg #lines line.axis_supply.allied_supply {
stroke: darkorange;
+ stroke-opacity: 0.6;
}
/* UNITS */
diff --git a/play.js b/play.js
index 9ab21b3..a200363 100644
--- a/play.js
+++ b/play.js
@@ -69,6 +69,7 @@ function set_has(set, item) {
let ui = {
hexes: [],
sides: [],
+ lines: [],
hex_x: [],
hex_y: [],
units: [],
@@ -251,7 +252,7 @@ function focus_stack(stack, hex) {
console.log("FOCUS STACK", stack, hex)
ui.focus = stack
update_map()
- return stack.length <= 1 || hex === hexdeploy + view.month
+ return stack.length <= 1 || is_setup_hex(hex)
}
return true
}
@@ -309,6 +310,11 @@ document.getElementById("map").addEventListener("mousedown", function (evt) {
}
})
+function for_each_side_in_path(path, fn) {
+ for (let i = 1; i < path.length; ++i)
+ fn(to_side_id(path[i-1], path[i]))
+}
+
function on_focus_hex(evt) {
let h = evt.target.hex
let text = "(" + h + ") " + hex_name[h]
@@ -401,11 +407,13 @@ function show_supply(reply) {
view.allied_supply_line = reply.allied_supply_line
for (let x of all_hexes) {
ui.hexes[x].classList.toggle("axis_supply", is_hex_axis_supply(x))
- for (let s = 0; s < 3; ++s)
- ui.sides[x*3+s].classList.toggle("axis_supply", is_side_axis_supply_line(x*3+s))
ui.hexes[x].classList.toggle("allied_supply", is_hex_allied_supply(x))
- for (let s = 0; s < 3; ++s)
- ui.sides[x*3+s].classList.toggle("allied_supply", is_side_allied_supply_line(x*3+s))
+ for (let s = 0; s < 3; ++s) {
+ if (ui.lines[x*3+s]) {
+ ui.lines[x*3+s].classList.toggle("axis_supply", is_side_axis_supply_line(x*3+s))
+ ui.lines[x*3+s].classList.toggle("allied_supply", is_side_allied_supply_line(x*3+s))
+ }
+ }
}
}
@@ -416,8 +424,10 @@ function hide_supply() {
ui.hexes[x].classList.toggle("axis_supply", false)
ui.hexes[x].classList.toggle("allied_supply", false)
for (let s = 0; s < 3; ++s) {
- ui.sides[x*3+s].classList.toggle("axis_supply", false)
- ui.sides[x*3+s].classList.toggle("allied_supply", false)
+ if (ui.lines[x*3+s]) {
+ ui.lines[x*3+s].classList.toggle("axis_supply", false)
+ ui.lines[x*3+s].classList.toggle("allied_supply", false)
+ }
}
}
}
@@ -440,6 +450,21 @@ const hexdeploy = map_w * map_h
let hexnext = [ 1, map_w, map_w-1, -1, -map_w, -(map_w-1) ]
+function to_side_id(a, b) {
+ if (a > b) {
+ let c = b
+ b = a
+ a = c
+ }
+ if (a + hexnext[0] === b)
+ return a * 3 + 0
+ else if (a + hexnext[1] === b)
+ return a * 3 + 1
+ else if (a + hexnext[2] === b)
+ return a * 3 + 2
+ throw new Error("not a hexside " + a + " to " + b)
+}
+
function build_hexes() {
let yoff = 4
let xoff = 62
@@ -482,6 +507,16 @@ function build_hexes() {
side.side = side_id
}
+ function add_path(x1, y1, x2, y2, side_id) {
+ let line = ui.lines[side_id] = document.createElementNS(svgNS, "line")
+ line.setAttribute("class", "path")
+ line.setAttribute("x1", x1)
+ line.setAttribute("y1", y1)
+ line.setAttribute("x2", x2)
+ line.setAttribute("y2", y2)
+ document.getElementById("mapsvg").getElementById("lines").appendChild(line)
+ }
+
function add_hex(x, y) {
let sm_hex_w = hex_w - 8
let sm_hex_h = sm_hex_w / sqrt(3) * 2
@@ -525,18 +560,18 @@ function build_hexes() {
hex.classList.add("refit")
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 hex_id = 0; hex_id < map_w * map_h; ++hex_id) {
+ // Add hex sides
+ {
+ for (let s = 0; s < 3; ++s) {
+ let next_id = hex_id + hexnext[s]
+ let side_id = hex_id * 3 + s
+ add_line(ui.hex_x[hex_id], ui.hex_y[hex_id], s, side_id)
+ if (hex_exists[hex_id] && hex_exists[next_id])
+ add_path(ui.hex_x[hex_id], ui.hex_y[hex_id], ui.hex_x[next_id], ui.hex_y[next_id], side_id)
}
}
}
@@ -621,11 +656,13 @@ function update_map() {
let hex = unit_hex(u)
if (hex >= hexdeploy + view.month + 10)
hex = 0
- if (hex === hexdeploy + view.month) {
+ if (is_setup_hex(hex)) {
if (player === "Axis" && !is_axis_unit(u))
hex = 0
if (player === "Allied" && !is_allied_unit(u))
hex = 0
+ if (player !== "Axis" && player !== "Allied")
+ hex = 0
}
if (view.month <= 10 && hex === MALTA)
hex = 0
@@ -671,7 +708,7 @@ function update_map() {
let start_y = ui.hex_y[hex]
let wrap = 6
- if (hex === hexdeploy + view.month) {
+ if (is_setup_hex(hex)) {
start_x = 1095
start_y = 25 + 8
}
@@ -687,7 +724,7 @@ function update_map() {
let e = ui.units[u]
let x, y, z
- if (hex === hexdeploy + view.month) {
+ if (is_setup_hex(hex)) {
if (view.month == 8)
wrap = 14
else
@@ -761,7 +798,7 @@ function update_cards() {
ui.cards[i+28].classList.toggle("hide", i >= view.cards[1])
} else {
for (let i = 0; i < 42; ++i)
- ui.cards[i+28].classList.add("hide")
+ ui.cards[i].classList.add("hide")
}
}
diff --git a/rules.js b/rules.js
index b650c97..314d7dc 100644
--- a/rules.js
+++ b/rules.js
@@ -1610,6 +1610,16 @@ function print_path(who, from, to, road) {
log(">" + p.join(" - ") + ".")
}
+function show_path(from, to, p, speed) {
+ let road = can_move_road(to, speed)
+ p.push(to)
+ while (to && to !== from) {
+ to = path_from[road][to]
+ p.push(to)
+ }
+ return p
+}
+
// normal move: may not leave battle hex. may engage any enemy. may move freely.
// normal withdrawal: may not leave battle hex. may engage disrupted enemy. must follow supply lines.
// retreat move: must leave battle hex via friendly side. may ignore disrupted enemy. may move freely.
@@ -1834,6 +1844,18 @@ function search_path_redeploy_bfs(cost, start, road) {
}
}
+function can_move_road(to, speed) {
+ if (path_cost[4][to] <= speed + 4)
+ return 4
+ if (path_cost[2][to] <= speed + 2)
+ return 2
+ if (path_cost[1][to] <= speed + 1)
+ return 1
+ if (path_cost[0][to] <= speed)
+ return 0
+ return -1
+}
+
function can_move_to(to, speed) {
if (path_cost[4][to] <= speed + 4)
return true
@@ -3370,47 +3392,44 @@ function goto_overrun(where) {
goto_rout(where, true, null)
}
+function do_gen_move_to(from, to, speed) {
+ if (can_move_to(to, speed)) {
+ gen_action_hex(to)
+ // view.path[to] = show_path(from, to, [], speed)
+ } else if (can_move_to(to, speed + 1)) {
+ gen_action_forced_march(to)
+ // view.path[to] = show_path(from, to, [], speed + 1)
+ }
+}
+
function gen_move() {
let rommel1 = (game.rommel === 1) ? 1 : 0
let rommel2 = (game.rommel === 2) ? 1 : 0
let speed = unit_speed[game.selected]
let from = unit_hex(game.selected)
+ // view.path = {}
+
if (!game.to1 && game.from1 === from) {
for (let to of all_hexes) {
- if (to != from) {
- if (can_move_to(to, speed + rommel1))
- gen_action_hex(to)
- else if (can_move_to(to, speed + 1 + rommel1))
- gen_action_forced_march(to)
- }
+ if (to != from)
+ do_gen_move_to(from, to, speed + rommel1)
}
}
if (!game.to2 && game.from2 === from) {
for (let to of all_hexes) {
- if (to != from) {
- if (can_move_to(to, speed + rommel2))
- gen_action_hex(to)
- else if (can_move_to(to, speed + 1 + rommel2))
- gen_action_forced_march(to)
-
- }
+ if (to != from)
+ do_gen_move_to(from, to, speed + rommel2)
}
}
if (game.to1 && is_hex_or_adjacent_to(from, game.from1)) {
- if (can_move_to(game.to1, speed + rommel1))
- gen_action_hex(game.to1)
- else if (can_move_to(game.to1, speed + 1 + rommel1))
- gen_action_forced_march(game.to1)
+ do_gen_move_to(from, game.to1, speed + rommel1)
}
if (game.to2 && is_hex_or_adjacent_to(from, game.from2)) {
- if (can_move_to(game.to2, speed + rommel2))
- gen_action_hex(game.to2)
- else if (can_move_to(game.to2, speed + 1 + rommel2))
- gen_action_forced_march(game.to2)
+ do_gen_move_to(from, game.to2, speed + rommel2)
}
}
@@ -3419,24 +3438,32 @@ function gen_withdraw() {
let speed = unit_speed[game.selected]
let from = unit_hex(game.selected)
+ // view.path = {}
+
// Group Move Withdraw
if (!game.to1) {
for (let to of all_hexes) {
if (to != from) {
- if (can_move_to(to, speed + rommel1) && set_has(game.withdraw, to))
+ if (can_move_to(to, speed + rommel1) && set_has(game.withdraw, to)) {
gen_action_hex(to)
- else if (can_move_to(to, speed + 1 + rommel1) && set_has(game.withdraw, to))
+ // view.path[to] = show_path(from, to, [], speed + rommel1)
+ } else if (can_move_to(to, speed + 1 + rommel1) && set_has(game.withdraw, to)) {
gen_action_forced_march(to)
+ // view.path[to] = show_path(from, to, [], speed + 1 + rommel1)
+ }
}
}
}
// Regroup Move Withdraw
if (game.to1) {
- if (can_move_to(game.to1, speed + rommel1))
+ if (can_move_to(game.to1, speed + rommel1)) {
gen_action_hex(game.to1)
- else if (can_move_to(game.to1, speed + 1 + rommel1))
+ // view.path[game.to1] = show_path(from, game.to1, [], speed + rommel1)
+ } else if (can_move_to(game.to1, speed + 1 + rommel1)) {
gen_action_forced_march(game.to1)
+ // view.path[game.to1] = show_path(from, game.to1, [], speed + 1 + rommel1)
+ }
}
}
@@ -3588,8 +3615,18 @@ states.forced_march_via = {
prompt() {
view.prompt = `Move: Select which path to take.`
view.selected = game.hexside.who
- for (let x of game.hexside.via)
+
+ // view.path = {}
+
+ let rommel = (game.hexside.move === game.rommel) ? 1 : 0
+ let from = unit_hex(game.hexside.who)
+ let speed = unit_speed[game.hexside.who]
+ search_move(from, speed + 1 + rommel)
+
+ for (let x of game.hexside.via) {
gen_action_hex(x)
+ // view.path[x] = show_path(from, x, [ game.hexside.to ], speed + rommel)
+ }
},
hex(via) {
let rommel = (game.hexside.move === game.rommel) ? 1 : 0
@@ -3609,11 +3646,23 @@ states.engage_via = {
prompt() {
view.prompt = `Move: Select which hex side to cross.`
view.selected = game.hexside.who
- for (let i = 0; i < game.hexside.via.length; ++i)
+
+ // view.path = {}
+
+ let rommel = (game.hexside.move === game.rommel) ? 1 : 0
+ let who = game.hexside.who
+ let from = unit_hex(who)
+ let speed = unit_speed[who]
+ search_move(from, speed + rommel)
+
+ for (let i = 0; i < game.hexside.via.length; ++i) {
+ let x = game.hexside.via[i]
if (game.hexside.forced[i])
- gen_action_forced_march(game.hexside.via[i])
+ gen_action_forced_march(x)
else
- gen_action_hex(game.hexside.via[i])
+ gen_action_hex(x)
+ // view.path[x] = show_path(from, x, [ game.hexside.to ], speed + rommel)
+ }
},
forced_march(via) {
let rommel = (game.hexside.move === game.rommel) ? 1 : 0
@@ -6069,6 +6118,7 @@ states.free_deployment = {
let axis = (game.active === AXIS)
view.prompt = `Setup: ${game.active} Deployment.`
+ view.deploy = 1
// view.prompt = `Setup: Deploy units in a supplied location in the setup area.`
let done = true