"use strict" // vim: set nowrap: /* globals data, view, action_button, action_button_with_argument, confirm_action_button, send_action, params */ function toggle_pieces() { // Cycle between showing everything, only pieces, and nothing. let hidden_pieces = ui.pieces_element.classList.contains("hide") let hidden_markers = ui.markers_element.classList.contains("hide") if (hidden_pieces && hidden_markers) { ui.pieces_element.classList.remove("hide") ui.markers_element.classList.remove("hide") } else if (hidden_pieces) { ui.markers_element.classList.add("hide") } else { ui.pieces_element.classList.add("hide") } } function toggle_shift() { document.body.classList.toggle("shift") } /* DATA */ const P_FRANCE = 0 const P_BAVARIA = 1 const P_PRUSSIA = 2 const P_SAXONY = 3 const P_PRAGMATIC = 4 const P_AUSTRIA = 5 const last_city = data.cities.name.length - 1 const ELIMINATED = data.cities.name.length const REMOVED = ELIMINATED + 1 const ELIMINATED_TRAIN_X = 1065 const ELIMINATED_TRAIN_Y = 210 const ELIMINATED_DISC_X = 1365 const ELIMINATED_DISC_Y = 210 const ELIMINATED_GENERAL_X = 1040 const ELIMINATED_GENERAL_Y = 160 const ELIMINATED_GENERAL_DX = 50 const power_class = [ "france", "bavaria", "prussia", "saxony", "pragmatic", "austria" ] const power_name = [ "France", "Bavaria", "Prussia", "Saxony", "Pragmatic", "Austria" ] const all_powers = [ 0, 1, 2, 3, 4, 5 ] const all_power_generals = [ [ 0, 1, 2, 3, 4 ], [ 5 ], [ 6, 7, 8, 9 ], [ 10 ], [ 11, 12, 13 ], [ 14, 15, 16, 17, 18, 19 ], ] const all_power_trains = [ [ 20, 21 ], [ 22 ], [ 23, 24 ], [ 25 ], [ 26 ], [ 27, 28, 29 ], ] const piece_power = [ P_FRANCE, P_FRANCE, P_FRANCE, P_FRANCE, P_FRANCE, P_BAVARIA, P_PRUSSIA, P_PRUSSIA, P_PRUSSIA, P_PRUSSIA, P_SAXONY, P_PRAGMATIC, P_PRAGMATIC, P_PRAGMATIC, P_AUSTRIA, P_AUSTRIA, P_AUSTRIA, P_AUSTRIA, P_AUSTRIA, P_AUSTRIA, P_FRANCE, P_FRANCE, P_BAVARIA, P_PRUSSIA, P_PRUSSIA, P_SAXONY, P_PRAGMATIC, P_AUSTRIA, P_AUSTRIA, P_AUSTRIA, P_AUSTRIA, P_AUSTRIA ] const piece_abbr = [ "F1", "F2", "F3", "F4", "F5", "B1", "P1", "P2", "P3", "P4", "S1", "PA1", "PA2", "PA3", "A1", "A2", "A3", "A4", "A5", "A6", ] const piece_name = [ "Moritz", "Belle-Isle", "Broglie", "Maillebois", "Noailles", "Törring", "Friedrich", "Schwerin", "Leopold", "Dessauer", "Rutowski", "George II", "Cumberland", "Earl of Stair", "Karl", "Traun", "Khevenhüller", "Batthyány", "Neipperg", "Arenberg", "French ST", "French ST", "Bavarian ST", "Prussian ST", "Prussian ST", "Saxon ST", "Pragmatic Army ST", "Austrian ST", "Austrian ST", "Austrian ST", "hussars", "hussars", ] let suit_class = [ "spades", "clubs", "hearts", "diamonds", "reserve" ] let suit_letter = [ "S", "C", "H", "D", "R" ] function to_deck(c) { return c >> 7 } function to_suit(c) { return (c >> 4) & 7 } function to_value(c) { if (to_suit(c) === 4) return 8 return c & 15 } /* SHOW PATHS */ const svgNS = "http://www.w3.org/2000/svg" var _show_path_pcs = [] 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 = 18 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) 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(ps, ss) { _show_path_pcs = ps for (let p of _show_path_pcs) on_focus_piece_tip(p) hide_move_path() _show_path = ss show_move_path(view.pos[ps[0]] !== ss[ss.length-1]) ui.status.textContent = ss.map(s => data.cities.name[s]).join(" - ") } function on_blur_path_tip() { for (let p of _show_path_pcs) on_blur_piece_tip(p) hide_move_path() ui.status.textContent = "" } function show_move_path(tip_end) { if (_show_path && _show_path.length > 0) { for (let i = 0; i < _show_path.length; ++i) ui.cities[_show_path[i]].classList.add("move") if (tip_end) ui.cities[_show_path[_show_path.length-1]].classList.add("tip") 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 && _show_path.length > 0) { for (let i = 0; i < _show_path.length; ++i) ui.cities[_show_path[i]].classList.remove("move") ui.cities[_show_path[_show_path.length-1]].classList.remove("tip") 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_FRANCE, P_BAVARIA, P_PRUSSIA, P_SAXONY, P_PRAGMATIC, P_AUSTRIA, P_AUSTRIA+1 ] const panel_start = { "Observer": P_FRANCE, "Louis XV": P_FRANCE, "Frederick": P_PRUSSIA, "Maria Theresa": P_AUSTRIA, } function remember_position(e) { if (e.parentElement) { let rect = e.getBoundingClientRect() e.my_parent = e.parentElement e.my_x = rect.x e.my_y = rect.y } else { e.my_parent = null e.my_x = 0 e.my_y = 0 } } function animate_position(e) { if (e.parentElement) { if (e.my_parent) { let rect = e.getBoundingClientRect() let dx = e.my_x - rect.x let dy = e.my_y - rect.y if (dx !== 0 || dy !== 0) { e.animate( [ { transform: `translate(${dx}px, ${dy}px)`, }, { transform: "translate(0, 0)", }, ], { duration: 333, easing: "ease" } ) } } } } function sort_power_panel(animate) { let start = panel_start[params.role] | 0 if (animate) for (let i = 0; i < 7; ++i) remember_position(ui.power_panel[i]) ui.power_panel_list.replaceChildren() for (let i = 0; i < 7; ++i) { let p = panel_order[(i + start) % 7] ui.power_panel_list.appendChild(ui.power_panel[p]) } if (view && view.actions) ui.power_panel_list.prepend(ui.power_panel[view.power]) if (animate) for (let i = 0; i < 7; ++i) animate_position(ui.power_panel[i]) } /* BUILD UI */ const ui = { prompt: document.getElementById("prompt"), status: document.getElementById("status"), header: document.querySelector("header"), spaces_element: document.getElementById("spaces"), pieces_element: document.getElementById("pieces"), markers_element: document.getElementById("markers"), political_display: document.getElementById("political_display"), discard: [ document.getElementById("discard_1"), document.getElementById("discard_2"), document.getElementById("discard_3"), document.getElementById("discard_4"), ], power_panel_list: document.getElementById("power_panel_list"), power_header: [ document.getElementById("hand_france_header"), document.getElementById("hand_bavaria_header"), document.getElementById("hand_prussia_header"), document.getElementById("hand_saxony_header"), document.getElementById("hand_pragmatic_header"), document.getElementById("hand_austria_header"), document.getElementById("political_header"), ], power_panel: [ document.getElementById("hand_france_panel"), document.getElementById("hand_bavaria_panel"), document.getElementById("hand_prussia_panel"), document.getElementById("hand_saxony_panel"), document.getElementById("hand_pragmatic_panel"), document.getElementById("hand_austria_panel"), document.getElementById("political_panel"), ], hand: [ document.getElementById("hand_france"), document.getElementById("hand_bavaria"), document.getElementById("hand_prussia"), document.getElementById("hand_saxony"), document.getElementById("hand_pragmatic"), document.getElementById("hand_austria"), ], cities: [], roads: [], action_register: [], } function register_action(target, action, id) { target.my_id = id target.my_action = action target.onmousedown = (evt) => on_click_action(evt, target) ui.action_register.push(target) } function on_click_action(evt, target) { if (evt.button === 0) if (send_action(target.my_action, target.my_id)) evt.stopPropagation() } function process_actions() { for (let target of ui.action_register) target.classList.toggle("action", is_action(target.my_action, target.my_id)) } function is_action(action, arg) { if (arg === undefined) return !!(view.actions && view.actions[action] === 1) return !!(view.actions && view.actions[action] && set_has(view.actions[action], arg)) } function create_element(action, id, style) { let e = document.createElement("div") e.className = style register_action(e, action, id) return e } function create_piece(action, id, style) { let e = document.createElement("div") e.className = style register_action(e, action, id) e.onmouseenter = on_focus_piece e.onmouseleave = on_blur_piece return e } function create_marker(style) { let e = document.createElement("div") e.className = style return e } function make_tc_deck(n) { for (let suit = 0; suit <= 3; ++suit) { for (let value = 2; value <= 10; ++value) { let c = (n << 7) | (suit << 4) | value ui.tc[c] = create_element("card", c, "card tc deck_" + (n+1) + " " + suit_class[suit] + " " + suit_letter[suit] + value) } } for (let value = 2; value <= 3; ++value) { let c = (n << 7) | (4 << 4) | value ui.tc[c] = create_element("card", c, "card tc deck_" + (n+1) + " reserve R") } } function make_tc_deck_back(n) { let list = [] for (let i = 0; i < 38; ++i) { let e = document.createElement("div") e.className = "card tc reverse " + n list.push(e) } return list } function make_tc_deck_pile(n) { let list = [] for (let i = 0; i < 10; ++i) { let e = document.createElement("div") e.className = "card tc pile reverse " + n list.push(e) } return list } function make_tc_deck_hand(n) { let list = [] for (let i = 0; i < 100; ++i) { let e = document.createElement("div") e.className = "card tc hand reverse " + n list.push(e) } return list } function make_political_card(fc) { let e = document.createElement("div") if (fc === 0) e.className = "card political reverse" else e.className = "card political c" + fc return e } function has_removed_all_pieces(pow) { for (let p of all_power_generals[pow]) if (view.pos[p] !== REMOVED) return false for (let p of all_power_trains[pow]) if (view.pos[p] !== REMOVED) return false return true } function on_init() { ui.pieces = [ create_piece("piece", 0, "piece cylinder france_1"), create_piece("piece", 1, "piece cylinder france_2"), create_piece("piece", 2, "piece cylinder france_3"), create_piece("piece", 3, "piece cylinder france_4"), create_piece("piece", 4, "piece cylinder france_5"), create_piece("piece", 5, "piece cylinder bavaria_1"), create_piece("piece", 6, "piece cylinder prussia_1"), create_piece("piece", 7, "piece cylinder prussia_2"), create_piece("piece", 8, "piece cylinder prussia_3"), create_piece("piece", 9, "piece cylinder prussia_4"), create_piece("piece", 10, "piece cylinder saxony_1"), create_piece("piece", 11, "piece cylinder pragmatic_1"), create_piece("piece", 12, "piece cylinder pragmatic_2"), create_piece("piece", 13, "piece cylinder pragmatic_3"), create_piece("piece", 14, "piece cylinder austria_1"), create_piece("piece", 15, "piece cylinder austria_2"), create_piece("piece", 16, "piece cylinder austria_3"), create_piece("piece", 17, "piece cylinder austria_4"), create_piece("piece", 18, "piece cylinder austria_5"), create_piece("piece", 19, "piece cylinder austria_6"), create_piece("piece", 20, "piece cube france"), create_piece("piece", 21, "piece cube france"), create_piece("piece", 22, "piece cube bavaria"), create_piece("piece", 23, "piece cube prussia"), create_piece("piece", 24, "piece cube prussia"), create_piece("piece", 25, "piece cube saxony"), create_piece("piece", 26, "piece cube pragmatic"), create_piece("piece", 27, "piece cube austria"), create_piece("piece", 28, "piece cube austria"), create_piece("piece", 29, "piece cube austria"), create_piece("piece", 30, "piece disc austria"), create_piece("piece", 31, "piece disc austria"), ] ui.troops = [] for (let i = 0; i < 20; ++i) ui.troops[i] = create_marker("hide") for (let e of ui.troops) ui.pieces_element.appendChild(e) /* ui.conquest = [] ui.retro = [] for (let s of all_objectives) { for (let pow = 0; pow < 7; ++pow) { if (set_has(objective1[pow], s) || set_has(objective2[pow], s)) { ui.conquest[s] = create_conquest("marker conquest " + power_class[pow], s) ui.retro[s] = create_conquest("marker retroactive " + power_class[pow], s) } } } */ ui.tc = [] make_tc_deck(0) make_tc_deck(1) make_tc_deck(2) make_tc_deck(3) ui.tc_back = [ make_tc_deck_back("deck_1"), make_tc_deck_back("deck_2"), make_tc_deck_back("deck_3"), make_tc_deck_back("deck_4"), ] ui.tc_hand = [ make_tc_deck_pile("deck_1"), make_tc_deck_pile("deck_1"), make_tc_deck_pile("deck_1"), make_tc_deck_pile("deck_1"), make_tc_deck_pile("deck_1"), make_tc_deck_pile("deck_1"), ] ui.tc_discard = [ make_tc_deck_pile("deck_1"), make_tc_deck_pile("deck_2"), make_tc_deck_pile("deck_3"), make_tc_deck_pile("deck_4"), ] ui.combat = document.createElement("div") ui.combat.id = "combat" ui.combat.style.zIndex = 2000 ui.tcbreak = document.createElement("div") ui.tcbreak.className = "draw-break" ui.political = [] for (let fc = 0; fc <= 18; ++fc) ui.political[fc] = make_political_card(fc) for (let a = 0; a <= last_city; ++a) { let e = (ui.cities[a] = document.createElement("div")) let x = data.cities.x[a] let y = data.cities.y[a] if (set_has(data.type.major_fortress, a)) { e.className = "space major_fortress" x -= 16 + 6 + 4 y -= 16 + 6 + 4 } else if (set_has(data.type.minor_fortress, a)) { e.className = "space minor_fortress" x -= 14 + 5 + 4 y -= 14 + 5 + 4 } else if (set_has(data.type.box, a)) { e.className = "space box" if (data.cities.name[a] === "England") { e.className = "space box england" x -= 24 + 4 y -= 28 + 4 } else { x -= 22 + 4 y -= 22 + 4 } } else { e.className = "space city" x -= 9 + 5 + 4 y -= 9 + 5 + 4 } if (set_has(data.country.Austria, a)) e.classList.add("country_austria") if (set_has(data.country.France, a)) e.classList.add("country_france") if (set_has(data.country.Prussia, a)) e.classList.add("country_prussia") if (set_has(data.country.Netherlands, a)) e.classList.add("country_netherlands") if (set_has(data.country.Silesia, a)) e.classList.add("country_silesia") if (set_has(data.country.Saxony, a)) e.classList.add("country_saxony") if (set_has(data.country.Bavaria, a)) e.classList.add("country_bavaria") if (set_has(data.country.Poland, a)) e.classList.add("country_poland") if (set_has(data.country.Empire, a)) e.classList.add("country_empire") register_action(e, "space", a) e.onmouseenter = on_focus_city e.onmouseleave = on_blur_city //e.classList.add("hide") e.style.left = x + "px" e.style.top = y + "px" 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, "road") for (let b of data.cities.roads[a]) if (a < b) make_road(a, b, "road") } sort_power_panel(false) update_favicon() } on_init() /* TOOLTIPS */ function on_click_city_tip(loc) { ui.cities[loc].scrollIntoView({ block: "center", inline: "center", behavior: "smooth" }) } function on_focus_city_tip(s) { ui.cities[s].classList.add("tip") } function on_blur_city_tip(s) { ui.cities[s].classList.remove("tip") } function on_click_piece_tip(loc) { ui.pieces[loc].scrollIntoView({ block: "center", inline: "center", behavior: "smooth" }) } function on_focus_piece_tip(s) { ui.pieces[s].classList.add("tip") } function on_blur_piece_tip(s) { ui.pieces[s].classList.remove("tip") } function on_focus_city(evt) { ui.status.textContent = data.cities.name[evt.target.my_id] } function on_blur_city() { ui.status.textContent = "" } function on_focus_piece(evt) { let p = evt.target.my_id if (p < 20 && view.troops[p] > 0) ui.status.textContent = piece_name[evt.target.my_id] + " (" + view.troops[p] + " troops)" else ui.status.textContent = piece_name[evt.target.my_id] } function on_blur_piece() { ui.status.textContent = "" } /* UPDATE UI */ function layout_general_offset(g, s) { // if not selected: number of unselected generals below us // if not selected: (number of unselected generals + 1) + number of selected generals below us if (!set_has(view.selected, g)) { let n = 0 for (let i = g+1; i < 20; ++i) if (view.pos[i] === s && !set_has(view.selected, i)) ++n return n } else { let n = 0 for (let i = 0; i < 20; ++i) if (view.pos[i] === s && !set_has(view.selected, i)) ++n if (n > 0) ++n for (let i = g+1; i < 20; ++i) if (view.pos[i] === s && set_has(view.selected, i)) ++n return n } } function layout_general_offset_elim(g) { let n = 0 let p = get_cylinder_power(g) for (let i of all_power_generals[p]) if (i > g && view.pos[i] === ELIMINATED) ++n return n } function layout_train_offset(g, s) { let n = 0 for (let i = g+1; i < 35; ++i) if (view.pos[i] === s) ++n return n } function get_cylinder_power(id) { for (let p of all_powers) if (set_has(all_power_generals[p], id)) return p return -1 } function layout_general(id, s) { let x, y, n if (s === REMOVED) { if (ui.pieces[id].parentElement === ui.pieces_element) e.remove() if (ui.troops[id].parentElement === ui.pieces_element) e.remove() return } if (s === ELIMINATED) { n = layout_general_offset_elim(id) x = ELIMINATED_GENERAL_X + ELIMINATED_GENERAL_DX * get_cylinder_power(id) y = ELIMINATED_GENERAL_Y } else { n = layout_general_offset(id, s) x = data.cities.x[s] y = data.cities.y[s] } let selected = set_has(view.selected, id) let e = ui.pieces[id] if (e.parentElement !== ui.pieces_element) ui.pieces_element.appendChild(e) e.style.left = (x - 21) + "px" e.style.top = (y - 29 - 15 * n) + "px" e.style.zIndex = y + n e.classList.toggle("selected", selected) e.classList.toggle("oos", (view.oos & (1 <> 1 let y = (data.cities.y[view.attacker] + data.cities.y[view.defender]) >> 1 ui.combat.style.left = x - 20 + "px" ui.combat.style.top = y - 20 + "px" } function create_conquest(style, s) { let x = data.cities.x[s] let y = data.cities.y[s] let e = document.createElement("div") e.dataset.id = s e.style.left = (x - 16) + "px" e.style.top = (y - 16) + "px" e.className = style return e } function update_favicon() { let favicon = document.querySelector('link[rel="icon"]') switch (params.role) { case "Louis XV": favicon.href = "favicon/louis.png"; break case "Frederick": favicon.href = "favicon/fritz.png"; break default: case "Maria Theresa": favicon.href = "favicon/maria.png"; break } } function cmp_tc(a, b) { let ax = (to_suit(a) << 7) + (to_value(a) << 3) + to_deck(a) let bx = (to_suit(b) << 7) + (to_value(b) << 3) + to_deck(b) return ax - bx } const colorize_S = '\u2660' const colorize_C = '\u2663' const colorize_H = '\u2665' const colorize_D = '\u2666' const colorize_R = '$1R' const colorize_1 = '$1' const colorize_2 = '$1' const colorize_3 = '$1' const colorize_4 = '$1' function colorize(text) { text = text.replace(/1\^(\d+)/g, colorize_1) text = text.replace(/2\^(\d+)/g, colorize_2) text = text.replace(/3\^(\d+)/g, colorize_3) text = text.replace(/4\^(\d+)/g, colorize_4) text = text.replace(/(\d+)R/g, colorize_R) text = text.replaceAll("\u2660", colorize_S) text = text.replaceAll("\u2663", colorize_C) text = text.replaceAll("\u2665", colorize_H) text = text.replaceAll("\u2666", colorize_D) return text } function on_prompt(text) { return colorize(text) } function on_update() { ui.header.classList.toggle("france", view.power === P_FRANCE) ui.header.classList.toggle("bavaria", view.power === P_BAVARIA) ui.header.classList.toggle("prussia", view.power === P_PRUSSIA) ui.header.classList.toggle("saxony", view.power === P_SAXONY) ui.header.classList.toggle("pragmatic", view.power === P_PRAGMATIC) ui.header.classList.toggle("austria", view.power === P_AUSTRIA) sort_power_panel(true) for (let p = 0; p < 20; ++p) layout_general(p, view.pos[p]) for (let p = 20; p < 30; ++p) layout_train(p, view.pos[p]) for (let p = 30; p < 32; ++p) layout_hussar(p, view.pos[p]) let back = [ 0, 0, 0, 0 ] for (let pow of all_powers) { /* let banner = `${power_name[pow]} \u2014 ${view.pt[pow]} troops` let m_obj = count_total_objectives(pow) if (m_obj > 0) { let n_obj = count_captured_objectives(pow) if (pow === P_AUSTRIA && view.oo) m_obj += "*" banner += ` \u2014 ${n_obj} of ${m_obj} objectives` } ui.power_header[pow].textContent = banner */ ui.hand[pow].replaceChildren() if (typeof view.hand[pow] === "number") { for (let i = 0; i < view.hand[pow]; ++i) ui.hand[pow].appendChild(ui.tc_hand[pow][i]) } else { view.hand[pow].sort(cmp_tc) for (let c of view.hand[pow]) { if ((c & 15) === 0) ui.hand[pow].appendChild(ui.tc_back[c>>7][back[c>>7]++]) else ui.hand[pow].appendChild(ui.tc[c]) } } } if (view.draw) { view.draw.sort(cmp_tc) if (view.hand[view.power].length > 0) ui.hand[view.power].appendChild(ui.tcbreak) for (let c of view.draw) ui.hand[view.power].appendChild(ui.tc[c]) } /* ui.political_display.replaceChildren() if (view.oo > 0) ui.political_display.appendChild(ui.tc[view.oo]) ui.political_display.appendChild(ui.fate[0]) if (typeof view.fate === "object") for (let c of view.fate) ui.political_display.appendChild(ui.fate[c]) */ for (let deck = 0; deck < 4; ++deck) { ui.discard[deck].replaceChildren() for (let i = 0; i < view.discard[deck]; ++i) ui.discard[deck].appendChild(ui.tc_discard[deck][i]) } ui.markers_element.replaceChildren() /* for (let s of view.conquest) ui.markers_element.appendChild(ui.conquest[s]) for (let s of view.retro) ui.markers_element.appendChild(ui.retro[s]) */ if (view.attacker !== undefined && view.defender !== undefined) { ui.markers_element.appendChild(ui.combat) layout_combat_marker() } for (let v = 16; v >= 0; --v) action_button_with_argument("value", v, v) for (let p = 0; p < 20; ++p) { action_button_with_argument("unstack", p, "Unstack " + piece_abbr[p]) action_button_with_argument("promote", p, "Promote " + piece_abbr[p]) action_button_with_argument("demote", p, "Demote " + piece_abbr[p]) } action_button("take", "Take") action_button("give", "Give") action_button("recruit", "Recruit") action_button("transfer", "Transfer") action_button("stop", "Stop") action_button("pass", "Pass") action_button("next", "Next") action_button("done", "Done") action_button("end_cards", "End card draw") action_button("end_setup", "End setup") action_button("end_recruit", "End recruit") action_button("end_movement", "End movement") action_button("end_combat", "End combat") action_button("end_supply", "End supply") action_button("end_turn", "End turn") confirm_action_button("confirm_end_movement", "End movement", "You have NOT moved ANY pieces!\nAre you sure you want to SKIP movement?") action_button("undo", "Undo") process_actions() } /* LOG */ function sub_piece(match, p1) { let x = p1 | 0 let n = piece_name[x] let p = power_class[piece_power[x]] return `${n}` } function sub_space(match, p1) { let x = p1 | 0 let n = data.cities.name[x] return `${n}` } function sub_path(pieces_and_spaces) { let ps = pieces_and_spaces[0].split(",") let ss = pieces_and_spaces[1].split(",") let x = ss[ss.length-1] let ps_name = ps.map(p => piece_name[p]).join(" and ") let ss_name = data.cities.name[x] return `${ps_name} to ${ss_name}.` } function on_log(text) { let p = document.createElement("div") if (text.match(/^>>/)) { text = text.substring(2) p.className = "ii" } if (text.match(/^>/)) { text = text.substring(1) p.className = "i" } if (text.match(/^!/)) { text = "Combat" p.className = "combat" } text = text.replace(/&/g, "&") text = text.replace(//g, ">") text = text.replaceAll(" 1 troops", " 1 troop") text = colorize(text) text = text.replace(/S(\d+)/g, sub_space) text = text.replace(/P(\d+)/g, sub_piece) if (text.startsWith("#")) { p.className = "h turn" text = text.substring(2) } else if (text.startsWith("=")) { p.className = "h " + power_class[text[1]] text = power_name[text[1]] } else if (text.startsWith("@")) { p.className = "move_tip" text = sub_path(text.substring(1).split(";")) } p.innerHTML = text return p } /* COMMON LIBRARY */ function array_insert(array, index, item) { for (let i = array.length; i > index; --i) array[i] = array[i - 1] array[index] = item } function set_has(set, item) { if (set === item) return true if (set === undefined) return false if (set === null) return false let a = 0 let b = set.length - 1 while (a <= b) { let m = (a + b) >> 1 let x = set[m] if (item < x) b = m - 1 else if (item > x) a = m + 1 else return true } return false } function set_add(set, item) { let a = 0 let b = set.length - 1 while (a <= b) { let m = (a + b) >> 1 let x = set[m] if (item < x) b = m - 1 else if (item > x) a = m + 1 else return } array_insert(set, a, item) } function set_add_all(set, other) { for (let item of other) set_add(set, item) }