From 329248efeb8681cac69c7db451c4601301d40049 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Tue, 4 Jun 2024 21:52:04 +0200 Subject: Brief movement line in log + movement path on mouse-over. --- data.js | 2 +- play.css | 19 +++++++++-- play.html | 1 + play.js | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++- rules.js | 82 ++++++++++++++++++++++++-------------------- tools/layout.svg | 18 +++++----- tools/parse-layout.js | 10 +++--- 7 files changed, 172 insertions(+), 55 deletions(-) diff --git a/data.js b/data.js index 828f758..4d9698d 100644 --- a/data.js +++ b/data.js @@ -1494,7 +1494,7 @@ const data = { [ 158, 548 ], [ 562, 622, 637 ], ], - major_roads: [ + main_roads: [ [], [], [], diff --git a/play.css b/play.css index 56b77ed..d5128be 100644 --- a/play.css +++ b/play.css @@ -120,8 +120,8 @@ body { min-height: 6px; } -#log .city_tip:hover { cursor: pointer; text-decoration: underline; } -#log .piece_tip:hover { cursor: pointer; text-decoration: underline; } +.city_tip .piece_tip, .path_tip { cursor: pointer; } +.city_tip:hover, .piece_tip:hover, .path_tip:hover { text-decoration: underline; } #log .h { background-color: tan; @@ -429,6 +429,21 @@ span.suit.reserve { font-weight: bold; font-family: "Source Serif SmText"; } .number.france { background-color: var(--color-france); } */ +/* ROADS */ + +svg .road { + stroke: white; + stroke-width: 6; + stroke-linecap: round; + stroke-dashpattern: 6 6; +} + +svg .main_road { + stroke: white; + stroke-width: 6; + stroke-linecap: round; +} + /* CARD COUNTING AIDS */ @media (hover: hover) { diff --git a/play.html b/play.html index 5bd90a8..66365b9 100644 --- a/play.html +++ b/play.html @@ -41,6 +41,7 @@
+
diff --git a/play.js b/play.js index 15264b3..22982d6 100644 --- a/play.js +++ b/play.js @@ -368,6 +368,79 @@ const the_austrian_theater_text = `

Prussia receives 5 TC per round. Every sub

Prussia wins by controlling all of her blue objectives in Bohemia, or if the game ends before Austria or the Imperial Army have won. ` +/* SHOW PATHS */ + +const svgNS = "http://www.w3.org/2000/svg" + +var _show_path = [] + +function make_road(a, b, type) { + let e = document.createElementNS(svgNS, "line") + e.setAttribute("class", type) + let x1 = data.cities.x[a] + let y1 = data.cities.y[a] + let x2 = data.cities.x[b] + let y2 = data.cities.y[b] + + let v = Math.hypot(x2 - x1, y2 - y1) + let dx = (x2 - x1) / v + let dy = (y2 - y1) / v + let r = 0 + x1 += r * dx + y1 += r * dy + x2 -= r * dx + y2 -= r * dy + + e.setAttribute("x1", x1) + e.setAttribute("y1", y1) + e.setAttribute("x2", x2) + e.setAttribute("y2", y2) + e.setAttribute("visibility", "hidden") + document.getElementById("roads").appendChild(e) + + if (!ui.roads[a]) ui.roads[a] = {} + if (!ui.roads[b]) ui.roads[b] = {} + ui.roads[a][b] = e + ui.roads[b][a] = e +} + +function on_focus_path_tip(list) { + on_focus_city_tip(list[list.length-1]) + hide_move_path() + _show_path = list + show_move_path() + ui.status.textContent = list.map(s => data.cities.name[s]).join(" - ") +} + +function on_blur_path_tip() { + if (_show_path.length > 0) { + on_blur_city_tip(_show_path[_show_path.length-1]) + hide_move_path() + } + ui.status.textContent = "" +} + +function show_move_path() { + if (_show_path) { + for (let i = 1; i < _show_path.length; ++i) { + let x = _show_path[i-1] + let y = _show_path[i] + ui.roads[x][y].setAttribute("visibility", "visible") + } + } +} + +function hide_move_path() { + if (_show_path) { + for (let i = 1; i < _show_path.length; ++i) { + let x = _show_path[i-1] + let y = _show_path[i] + ui.roads[x][y].setAttribute("visibility", "hidden") + } + _show_path = null + } +} + /* PANEL ORDER */ const panel_order = [ P_PRUSSIA, P_HANOVER, P_RUSSIA, P_SWEDEN, P_AUSTRIA, P_IMPERIAL, P_FRANCE, P_FRANCE+1 ] @@ -481,6 +554,7 @@ const ui = { ], cities: [], action_register: [], + roads: [], } function register_action(target, action, id) { @@ -735,6 +809,15 @@ function on_init() { ui.spaces_element.appendChild(e) } + for (let a = 0; a <= last_city; ++a) { + for (let b of data.cities.main_roads[a]) + if (a < b) + make_road(a, b, "main_road") + for (let b of data.cities.roads[a]) + if (a < b) + make_road(a, b, "road") + } + sort_power_panel(false) update_favicon() @@ -1289,6 +1372,12 @@ function sub_space(_match, p1) { return `${n}` } +function sub_path(list) { + let x = list[list.length-1] + let name = data.cities.name[x] + return `to ${name}` +} + const suit_icon = [ '\u2660', '\u2663', @@ -1332,7 +1421,11 @@ function on_log(text) { text = text.replace(/P(\d+)/g, sub_piece) text = text.replace(/C(\d+)/g, sub_tc) - if (text.match(/^\$(\d+)/)) { + if (text.startsWith("%")) { + p.className = "i" + text = sub_path(text.substring(1).split(",")) + } + else if (text.match(/^\$(\d+)/)) { let fx = parseInt(text.substring(1)) if (fx < 48) text = `

${fate_flavor_text[fx]}
${fate_effect_text[fx]}
` diff --git a/rules.js b/rules.js index 1506571..299b353 100644 --- a/rules.js +++ b/rules.js @@ -361,6 +361,23 @@ function log_selected() { log(game.selected.map(p => "P" + p).join(" and ")) } +function is_important_move(s) { + return set_has(game.move_conq, s) || set_has(game.move_reconq, s) || set_has(game.retro, s) +} + +function log_selected_move_path() { + if (0) { + log_selected() + log(">from S" + game.move_path[0]) + for (let i = 1; i < game.move_path.length; ++i) + if (is_important_move(game.move_path[i]) || i === game.move_path.length-1) + log(">to S" + game.move_path[i]) + } else { + log_selected() + log("%" + game.move_path.join(",")) + } +} + /* OBJECTIVES */ const all_objectives = [] @@ -1365,10 +1382,10 @@ states.movement = { else prompt("Move your generals and supply trains.") - if (done_trains && done_generals) - view.actions.end_movement = 1 - else + if (game.moved.length === 0) view.actions.confirm_end_movement = 1 + else + view.actions.end_movement = 1 }, piece(p) { push_undo() @@ -1386,11 +1403,12 @@ states.movement = { game.count = 0 - if (data.cities.major_roads[here].length > 0) - game.major = 1 + if (data.cities.main_roads[here].length > 0) + game.main = 1 else - game.major = 0 + game.main = 0 + game.move_path = [ here ] if (is_supply_train(p)) game.state = "move_supply_train" else @@ -1417,7 +1435,7 @@ states.movement = { function format_move(max) { let n = max - game.count - if (game.major) + if (game.main) return ` up to ${n} cities (${n+1} on main roads).` return ` up to ${n} cities.` } @@ -1496,7 +1514,7 @@ function can_move_general_to(to) { let from = game.pos[game.selected[0]] if (!can_continue_general_from(to)) return false - if (game.major && set_has(data.cities.major_roads[from], to)) + if (game.main && set_has(data.cities.main_roads[from], to)) return game.count < movement_range() return game.count < movement_range() - 1 } @@ -1538,7 +1556,7 @@ function move_general_to(to) { if (is_protected_from_conquest(from)) { set_add(game.retro, from) } else { - game.move_conq.push(from) + set_add(game.move_conq, from) set_add(game.conquest, from) } } @@ -1548,7 +1566,7 @@ function move_general_to(to) { if (is_protected_from_reconquest(from)) { set_add(game.retro, from) } else { - game.move_reconq.push(from) + set_add(game.move_reconq, from) set_delete(game.conquest, from) } } @@ -1603,8 +1621,8 @@ states.move_supply_train = { let who = game.selected[0] let here = game.pos[who] - if (game.count < 2 + game.major) - for (let next of data.cities.major_roads[here]) + if (game.count < 2 + game.main) + for (let next of data.cities.main_roads[here]) if (!has_any_piece(next)) gen_action_space(next) if (game.count < 2) @@ -1628,20 +1646,15 @@ states.move_supply_train = { let who = game.selected[0] let from = game.pos[who] - if (game.count === 0) { - log_selected() - log(">from S" + from) - } - - log(">to S" + to) + game.move_path.push(to) - if (!set_has(data.cities.major_roads[from], to)) - game.major = 0 + if (!set_has(data.cities.main_roads[from], to)) + game.main = 0 set_add(game.moved, who) game.pos[who] = to - if (++game.count === 2 + game.major) + if (++game.count === 2 + game.main) end_move_piece() }, } @@ -1708,8 +1721,8 @@ states.move_general = { } } - if (game.count < movement_range() + game.major) - for (let next of data.cities.major_roads[here]) + if (game.count < movement_range() + game.main) + for (let next of data.cities.main_roads[here]) if (can_move_general_to(next)) gen_action_space_or_piece(next) @@ -1749,17 +1762,12 @@ states.move_general = { let who = game.selected[0] let from = game.pos[who] - if (game.count === 0) { - log_selected() - log(">from S" + from) - } - - log(">to S" + to) + game.move_path.push(to) - if (!set_has(data.cities.major_roads[from], to)) - game.major = 0 + if (!set_has(data.cities.main_roads[from], to)) + game.main = 0 - if (move_general_to(to) || ++game.count === movement_range() + game.major) + if (move_general_to(to) || ++game.count === movement_range() + game.main) end_move_piece() }, } @@ -1807,6 +1815,9 @@ states.move_give = { } function end_move_piece() { + log_selected_move_path() + + delete game.move_path game.selected = null game.state = "movement" } @@ -2052,13 +2063,10 @@ function end_recruit() { if (game.recruit) { if (game.recruit.used.length > 0) { log_br() - log("Recruited") - log(">" + game.recruit.used.map(format_card).join(", ")) + log("Recruited " + game.recruit.troops + " troops with " + game.recruit.used.map(format_card).join(", ") + ".") map_for_each(game.recruit.pieces, (p,s) => { - log(">P" + p + " at S" + s) + log("Re-entered P" + p + " at S" + s + ".") }) - if (game.recruit.troops) - log(">" + game.recruit.troops + " troops") } // put back into hand unused cards diff --git a/tools/layout.svg b/tools/layout.svg index 3e7c511..c075e05 100644 --- a/tools/layout.svg +++ b/tools/layout.svg @@ -40,10 +40,10 @@ inkscape:window-height="480" id="namedview6" showgrid="false" - inkscape:zoom="1.3492621" + inkscape:zoom="1.1602604" inkscape:cx="417.73716" inkscape:cy="1363.1515" - inkscape:current-layer="g2856" + inkscape:current-layer="svg4" inkscape:document-rotation="0" showguides="false"> + width="2485" + height="1654" + sodipodi:insensitive="true" + id="image2" + style="display:inline" />