diff options
Diffstat (limited to 'play.js')
-rw-r--r-- | play.js | 1247 |
1 files changed, 1247 insertions, 0 deletions
@@ -0,0 +1,1247 @@ +"use strict" + +/* + global view, data, player, send_action, action_button, scroll_with_middle_mouse +*/ + +/* COMMON */ + +function set_has(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 true + } + return false +} + +function map_get(map, key, missing) { + let a = 0 + let b = (map.length >> 1) - 1 + while (a <= b) { + let m = (a + b) >> 1 + let x = map[m << 1] + if (key < x) + b = m - 1 + else if (key > x) + a = m + 1 + else + return map[(m << 1) + 1] + } + return missing +} + +/* DATA */ + +// Factions +const DS = 0 +const BK = 1 +const VE = 2 + +const NAME_DS = "DS" +const NAME_BK = "BK" +const NAME_VE = "VE" + +// Sequence of Play options +const ELIGIBLE = 0 +const SOP_LIMITED_COMMAND = 1 +const SOP_COMMAND_DECREE = 2 +const SOP_EVENT_OR_COMMAND = 3 +const SOP_PASS = 4 +const INELIGIBLE = 5 + +// Spaces +const S_ANDHRA = 0 +const S_BENGAL = 1 +const S_GONDWANA = 2 +const S_GUJARAT = 3 +const S_JAUNPUR = 4 +const S_KARNATAKA = 5 +const S_MADHYADESH = 6 +const S_MAHARASHTRA = 7 +const S_MALWA = 8 +const S_ORISSA = 9 +const S_RAJPUT_KINGDOMS = 10 +const S_SINDH = 11 +const S_TAMILAKAM = 12 +const S_DELHI = 13 +const S_MOUNTAIN_PASSES = 14 +const S_PUNJAB = 15 +const S_MONGOL_INVADERS = 16 +const S_DS_AVAILABLE = 17 +const S_BK_AVAILABLE = 18 +const S_VE_AVAILABLE = 19 +const S_BK_INF_2 = 20 +const S_BK_INF_4 = 21 +const S_VE_INF_1 = 22 +const S_VE_INF_2 = 23 +const S_VE_INF_3 = 24 +const S_VE_INF_4 = 25 + +const space_name = [ + "Andhra", + "Bengal", + "Gondwana", + "Gujarat", + "Jaunpur", + "Karnataka", + "Madhyadesh", + "Maharashtra", + "Malwa", + "Orissa", + "Rajput Kingdoms", + "Sindh", + "Tamilakam", + "Delhi", + "Mountain Passes", + "Punjab", + "Mongol Invaders", + "DS Available", + "BK Available", + "VE Available", +] + +/* LAYOUT DATA */ +// :r !node tools/parse-layout.js +const layout = { + "circles": { + "provinces": { + "Sindh": { + "cx": 65, + "cy": 393, + "rx": 34, + "ry": 34 + }, + "Rajput Kingdoms": { + "cx": 329, + "cy": 403, + "rx": 34, + "ry": 34 + }, + "Malwa": { + "cx": 605, + "cy": 572, + "rx": 34, + "ry": 34 + }, + "Jaunpur": { + "cx": 894, + "cy": 455, + "rx": 34, + "ry": 34 + }, + "Bengal": { + "cx": 1192, + "cy": 536, + "rx": 34, + "ry": 34 + }, + "Orissa": { + "cx": 1034, + "cy": 858, + "rx": 34, + "ry": 34 + }, + "Gondwana": { + "cx": 913, + "cy": 737, + "rx": 34, + "ry": 34 + }, + "Madhyadesh": { + "cx": 670, + "cy": 817, + "rx": 34, + "ry": 34 + }, + "Andhra": { + "cx": 743, + "cy": 1090, + "rx": 34, + "ry": 34 + }, + "Maharashtra": { + "cx": 438, + "cy": 969, + "rx": 34, + "ry": 34 + }, + "Gujarat": { + "cx": 220, + "cy": 678, + "rx": 34, + "ry": 34 + }, + "Karnataka": { + "cx": 550, + "cy": 1278, + "rx": 34, + "ry": 34 + }, + "Tamilakam": { + "cx": 704, + "cy": 1399, + "rx": 34, + "ry": 34 + } + }, + "mongol_invasion_regions": { + "Mountain Passes": { + "cx": 302, + "cy": 140, + "rx": 83, + "ry": 28 + }, + "Punjab": { + "cx": 478, + "cy": 220, + "rx": 58, + "ry": 19 + }, + "Delhi": { + "cx": 647, + "cy": 375, + "rx": 148, + "ry": 148 + } + } + }, + "rects": { + "available_boxes": { + "Mongol Invaders": { + "x": 24, + "y": 100, + "w": 177, + "h": 110 + }, + "DS Available": { + "x": 796, + "y": 91, + "w": 388, + "h": 223 + }, + "BK Available": { + "x": 21, + "y": 908, + "w": 238, + "h": 224 + }, + "VE Available": { + "x": 21, + "y": 1405, + "w": 239, + "h": 225 + } + }, + "tracks": { + "Track 24": { + "x": 1198, + "y": 403, + "w": 61, + "h": 61 + }, + "Track 18": { + "x": 1197, + "y": 14, + "w": 62, + "h": 63 + }, + "Track 0": { + "x": 15, + "y": 14, + "w": 62, + "h": 63 + }, + "BK Influence 0": { + "x": 18, + "y": 1186, + "w": 61, + "h": 63 + }, + "BK Influence 1": { + "x": 89, + "y": 1186, + "w": 61, + "h": 63 + }, + "BK Influence 2": { + "x": 160, + "y": 1186, + "w": 61, + "h": 63 + }, + "BK Influence 3": { + "x": 231, + "y": 1186, + "w": 61, + "h": 63 + }, + "BK Influence 4": { + "x": 302, + "y": 1186, + "w": 61, + "h": 63 + }, + "VE Influence 0": { + "x": 18, + "y": 1292, + "w": 61, + "h": 63 + }, + "VE Influence 1": { + "x": 89, + "y": 1292, + "w": 61, + "h": 63 + }, + "VE Influence 2": { + "x": 160, + "y": 1292, + "w": 61, + "h": 63 + }, + "VE Influence 3": { + "x": 231, + "y": 1291, + "w": 61, + "h": 63 + }, + "VE Influence 4": { + "x": 302, + "y": 1292, + "w": 61, + "h": 63 + } + }, + "sequence_of_play": { + "Limited Command": { + "x": 854, + "y": 1305, + "w": 90, + "h": 54 + }, + "Eligible Factions": { + "x": 854, + "y": 1367, + "w": 91, + "h": 201 + }, + "Pass": { + "x": 854, + "y": 1578, + "w": 90, + "h": 56 + }, + "Ineligible Factions": { + "x": 1166, + "y": 1367, + "w": 90, + "h": 201 + }, + "Command and Decree": { + "x": 1016, + "y": 1371, + "w": 77, + "h": 77 + }, + "Event or Command": { + "x": 1016, + "y": 1488, + "w": 77, + "h": 77 + } + } + } +} + +/* STATE */ + +function piece_space(p) { + return view.pieces[p] +} + +/* BUILD */ + +let ui = { + map: document.getElementById("map"), + favicon: document.getElementById("favicon"), + header: document.querySelector("header"), + status: document.getElementById("status"), + spaces: [], + control: [], + card_tip: document.getElementById("card_tip"), + this_card: document.getElementById("this_card"), + shaded_event: document.getElementById("shaded_event"), + unshaded_event: document.getElementById("unshaded_event"), + deck_outer: document.getElementById("deck_outer"), + deck_size: document.getElementById("deck_size"), + of_gods_and_kings: document.getElementById("of_gods_and_kings"), + dynasty_card: document.getElementById("dynasty_card"), + tokens: { + token_ds_vp: document.getElementById("token_ds_vp"), + token_bk_vp: document.getElementById("token_bk_vp"), + token_ve_vp: document.getElementById("token_ve_vp"), + token_bk_influence: document.getElementById("token_bk_influence"), + token_ve_influence: document.getElementById("token_ve_influence"), + token_mongol_cavalry: document.getElementById("token_mongol_cavalry"), + cavalry_1: document.getElementById("cavalry_1"), + cavalry_2: document.getElementById("cavalry_2"), + cavalry_3: document.getElementById("cavalry_3"), + cavalry_4: document.getElementById("cavalry_4"), + cavalry_5: document.getElementById("cavalry_5"), + cavalry_6: document.getElementById("cavalry_6"), + cavalry_7: document.getElementById("cavalry_7"), + cavalry_8: document.getElementById("cavalry_8"), + }, + pieces: [], + resources: [ + document.getElementById("ds_resources"), + document.getElementById("bk_resources"), + document.getElementById("ve_resources"), + ], + cylinder: [ + document.getElementById("ds_cylinder"), + document.getElementById("bk_cylinder"), + document.getElementById("ve_cylinder"), + ], +} + +function create(t, p, ...c) { + let e = document.createElement(t) + Object.assign(e, p) + e.append(c) + return e +} + +function register_action(e, action, id) { + e.my_action = action + e.my_id = id + e.onmousedown = on_click_action +} + +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 toggle_pieces() { + if (ui.map.classList.contains("hide_tokens")) { + ui.map.classList.remove("hide_tokens") + ui.map.classList.remove("hide_pieces") + } else if (ui.map.classList.contains("hide_pieces")) { + ui.map.classList.add("hide_tokens") + } else { + ui.map.classList.add("hide_pieces") + } +} + +function on_click_action(evt) { + if (evt.button === 0) + send_action(evt.target.my_action, evt.target.my_id) +} + +function init_ui() { + register_action(ui.this_card, "event", undefined) + register_action(ui.unshaded_event, "unshaded", undefined) + register_action(ui.shaded_event, "shaded", undefined) + register_action(ui.resources[DS], "resources", DS) + register_action(ui.resources[BK], "resources", BK) + register_action(ui.resources[VE], "resources", VE) + + ui.this_card.onmouseenter = on_focus_this_event + ui.this_card.onmouseleave = on_blur_event + ui.shaded_event.onmouseenter = on_focus_shaded_event + ui.shaded_event.onmouseleave = on_focus_this_event + ui.unshaded_event.onmouseenter = on_focus_unshaded_event + ui.unshaded_event.onmouseleave = on_focus_this_event + + for (let s = 0; s < 20; ++s) { + let e = null + + // provinces + if (s < S_DELHI) { + let { cx, cy } = layout.circles.provinces[space_name[s]] + ui.control[s] = e = create("div", { className: "token tributary" }) + e.style.left = (cx - 24) + "px" + e.style.top = (cy - 24) + "px" + document.getElementById("tokens").appendChild(e) + + ui.spaces[s] = e = create("div", { className: "space province" }) + e.style.left = (cx - 45) + "px" + e.style.top = (cy - 45) + "px" + e.style.width = (90 - 4) + "px" + e.style.height = (90 - 4) + "px" + register_action(e, "space", s) + document.getElementById("spaces").appendChild(e) + } + + // delhi & passes + if (s >= S_DELHI && s <= S_PUNJAB) { + let { cx, cy, rx, ry } = layout.circles.mongol_invasion_regions[space_name[s]] + ui.spaces[s] = e = create("div", { className: "space province" }) + e.style.left = (cx - rx) + "px" + e.style.top = (cy - ry) + "px" + e.style.width = (rx * 2 - 4) + "px" + e.style.height = (ry * 2 - 4) + "px" + register_action(e, "space", s) + document.getElementById("spaces").appendChild(e) + } + + // boxes + if (s >= S_MONGOL_INVADERS && s <= S_VE_AVAILABLE) { + let { x, y, w, h } = layout.rects.available_boxes[space_name[s]] + ui.spaces[s] = e = create("div", { className: "space" }) + e.style.left = x + "px" + e.style.top = y + "px" + e.style.width = (w - 4) + "px" + e.style.height = (h - 4) + "px" + register_action(e, "space", s) + document.getElementById("spaces").appendChild(e) + } + } + + function create_piece(c, action, id, x, y) { + let e = create("div", { + className: c, + my_action: action, + my_id: id, + my_x_offset: x, + my_y_offset: y, + onmousedown: on_click_action + }) + document.getElementById("pieces").appendChild(e) + return e + } + + function create_piece_list(faction, type, c, x, y) { + for (let p = first_piece[faction][type]; p <= last_piece[faction][type]; ++p) + ui.pieces[p] = create_piece(c, "piece", p, x, y) + } + + ui.pieces = [] + +return + + /* + <div class="piece ds governor" style="left:200px;top:380px"></div> + <div class="piece bk amir rebel" style="left:230px;top:380px"></div> + <div class="piece ve raja rebel" style="left:260px;top:380px"></div> + <div class="piece ds cube" style="left:210px;top:430px"></div> + <div class="piece mongol cube" style="left:245px;top:430px"></div> + <div class="piece ds disk" style="left:200px;top:480px"></div> + <div class="piece bk disk" style="left:250px;top:480px"></div> + <div class="piece ve disk" style="left:300px;top:480px"></div> + */ + + + create_piece_list(DS, DISK, "piece ds disk", -4, 10) + create_piece_list(DS, GOVERNOR, "piece ds governor", 0, 4) + create_piece_list(DS, CUBE, "piece ds cube", 0, 4) + + create_piece_list(BK, DISK, "piece ve disk", -4, 10) + create_piece_list(BK, AMIR, "piece ve amir", 2, 0) + + create_piece_list(VE, DISK, "piece ve disk", -4, 10) + create_piece_list(VE, RAJA, "piece ve raja", 2, 0) + + create_piece_list(MONGOLS, CUBE, "piece mongol cube", 2, 0) +} + +/* UPDATE */ + +function action_menu_item(action) { + let menu = document.getElementById(action + "_menu") + if (view.actions && action in view.actions) { + menu.classList.toggle("hide", false) + menu.classList.toggle("disabled", view.actions[action] === 0) + return 1 + } else { + menu.classList.toggle("hide", true) + return 0 + } +} + +function action_menu(menu, action_list) { + let x = 0 + for (let action of action_list) + x |= action_menu_item(action) + menu.classList.toggle("hide", !x) +} + +const LAYOUT_CACHE = { + Center: [], + Govt: [], + FARC: [], + AUC: [], + Cartels: [], + COIN: [], + INSURGENTS: [], +} + +function get_layout_xy(s, f = "Center") { + if (!LAYOUT_CACHE[f][s]) { + let id = (f !== "Center") ? data.spaces[s].id + " " + f : data.spaces[s].id + LAYOUT_CACHE[f][s] = LAYOUT[id] + } + return LAYOUT_CACHE[f][s] +} + +function filter_piece_list(list, space, faction, type) { + for (let i = first_piece[faction][type]; i <= last_piece[faction][type]; ++i) + if (view.pieces[i] === space) + list.push(ui.pieces[i]) +} + +function layout_available(faction, type, xorig, yorig) { + let list = [] + filter_piece_list(list, AVAILABLE, faction, type) + layout_pieces(list, xorig, yorig + 35, null, AVAILABLE) +} + +function layout_pieces(list, xorig, yorig, bases, shipments, s, faction) { + const dx = 17 + const dy = 11 + let off_x = 0 + let off_y = 0 + let rotate = 0 + + if (s >= 0) + rotate = (data.spaces[s].type === "mountain") ? 1 : 0 + + function layout_piece_rowcol(nrow, ncol, row, col, e, z) { + // basic piece size = 29x36 + let x = xorig - (row * dx - col * dx) - 15 + off_x + let y = yorig - (row * dy + col * dy) - 24 + off_y + let xo = e.my_x_offset + let yo = e.my_y_offset + e.style.left = (xo + x) + "px" + e.style.top = (yo + y) + "px" + e.style.zIndex = y + e.my_x = x + 15 + e.my_y = y + 24 + e.my_z = z + } + + if (list.length > 0) { + let nrow = Math.round(Math.sqrt(list.length)) + let ncol = Math.ceil(list.length / nrow) + let z = 50 + let i = 0 + if ((s >= 0 && s <= last_city) || s >= first_loc) { + off_x = (nrow - ncol) * 6 + off_y = (nrow - 1) * 8 + } + for (let row = 0; row < nrow; ++row) + for (let col = 0; col < ncol; ++col) + if (i < list.length) + layout_piece_rowcol(nrow, ncol, row, col, list[list.length-(++i)], z--) + } + + if (bases) + layout_dept_bases(bases, xorig + off_x, yorig + 12 + off_y, s) +} + +function place_piece(p, x, y, z) { + p.style.left = x + "px" + p.style.top = y + "px" + if (z) + p.style.zIndex = z + p.my_x = x + p.my_y = y + p.my_z = z +} + +function layout_dept_bases(list, xc, yc, s) { + if (list.length === 1) { + place_piece(list[0], xc - 20 + 32, yc - 10, 52) + } + if (list.length === 2) { + place_piece(list[0], xc - 20 + 18, yc - 0, 52) + place_piece(list[1], xc - 20 + 18 + 32, yc - 21, 51) + } + if (list.length === 3) { + // TODO + place_piece(list[0], xc - 20 + 18, yc - 0, 52) + place_piece(list[1], xc - 20 + 18 + 32, yc - 21, 51) + place_piece(list[2], xc - 20 + 18 + 32, yc - 21, 100) + } +} + +function layout_available_bases(list, x0, y0, cols, rows, dx, dy) { + let x = x0 + let y = y0 + for (let i = 0; i < list.length; ++i) { + place_piece(list[list.length-i-1], x - 44 - 6, y + 8) + y += dy + if (i % rows === rows - 1) { + x -= dx + y = y0 + } + } +} + +function layout_sop() { + let i, x, y, z + + // Eligible + x = 1164 - 22 + y = 480 + z = 1 + let order = data.card_order[view.deck[0]] + for (let faction of order) { + if (view.cylinder[faction] === ELIGIBLE) { + place_piece(ui.cylinder[faction], x, y, z) + y += 40 + z += 1 + } + } + + // Ineligible + x = 1510 - 22 + y = 480 + z = 1 + for (let faction = 0; faction < 4; ++faction) { + if (view.cylinder[faction] === INELIGIBLE) { + place_piece(ui.cylinder[faction], x, y, z) + y += 40 + z += 1 + } + } + + // Pass + x = 1164 - 22 - 24 + y = 688 - 28 + z = 1 + i = 0 + for (let faction = 0; faction < 4; ++faction) { + if (view.cylinder[faction] === SOP_PASS) { + place_piece(ui.cylinder[faction], x, y, z) + x += 48 + z += 1 + if (++i === 2) { x -= 72; y += 28 } + } + } + + for (let [i, x, y] of sop_xy) { + for (let faction = 0; faction < 4; ++faction) + if (view.cylinder[faction] === i) + place_piece(ui.cylinder[faction], x, y) + } +} + +function layout_score_cell(list, x, y, dx, dy) { + let z = 1 + if (list.length > 1) { + if (dy > 0) y -= 12 + if (dy < 0) y += 12 + if (dx > 0) x -= 12 + if (dx < 0) x += 12 + } + for (let p of list) { + if (p.classList.contains("token")) + place_piece(p, x - 24, y - 24, z) + else + place_piece(p, x - 22, y - 24, z) + x += dx + y += dy + z += 1 + } +} + +function layout_score() { + let list = [] + let x, y + for (let i = 0; i <= 24; ++i) { + list.length = 0 + + if (view.vp[DS] === i) list.push(ui.tokens.token_ds_vp) + if (view.vp[BK] === i) list.push(ui.tokens.token_bk_vp) + if (view.vp[VE] === i) list.push(ui.tokens.token_ve_vp) + + for (let faction = 0; faction < 3; ++faction) + if (view.resources[faction] === i) + list.push(ui.resources[faction]) + + // X: 15 -> 1198 (0-18) + // Y: 14 -> 403 (18-24) + + if (i < 18) y = 20 + else y = 20 + (i - 18) * 65 + + if (i < 18) x = 23 + (i * 65.6) + else x = 1204 + + x = Math.round(x) + 24 + y = Math.round(y) + 24 + + if (i < 17) layout_score_cell(list, x, y, 0, 28) + else if (i === 17) layout_score_cell(list, x, y, -18, 25) + else layout_score_cell(list, x, y, -41, 0) + } +} + +function update_rebels(faction, type, rebel) { + let p0 = first_piece[faction][type] + let p1 = last_piece[faction][type] + for (let i = 0, p = p0; p <= p1; ++i, ++p) { + if (underground & (1 << i)) + ui.pieces[p].classList.add("rebel") + else + ui.pieces[p].classList.remove("rebel") + } +} + +function make_card_class_name(c) { + return "card card_" + c + // TODO: + if (set_has([1,2,3,7,9,10,11,13], view.deck[0])) + return "card card_" + c + " u" + data.card_unshaded_lines[c] + " s" + data.card_shaded_lines[c] + " c" + else + return "card card_" + c + " u" + data.card_unshaded_lines[c] + " s" + data.card_shaded_lines[c] +} + +function update_player_active(name, x) { + if (roles[name]) + roles[name].element.classList.toggle("active", x) +} + +let once = true +function on_update() { + if (once) { + init_ui() + once = false + } + + switch (player) { + case "DS": ui.favicon.href = "images/Flag_DS.png"; break + case "BK": ui.favicon.href = "images/Flag_BK.png"; break + case "VE": ui.favicon.href = "images/Flag_VE.png"; break + } + + ui.header.classList.toggle("ds", view.current === DS) + ui.header.classList.toggle("bk", view.current === BK) + ui.header.classList.toggle("ve", view.current === VE) + + ui.tokens.token_bk_influence.classList.toggle("action", is_action("bk_inf")) + ui.tokens.token_ve_influence.classList.toggle("action", is_action("ve_inf")) + + ui.resources[DS].classList.toggle("action", is_action("resources", DS)) + ui.resources[BK].classList.toggle("action", is_action("resources", BK)) + ui.resources[VE].classList.toggle("action", is_action("resources", VE)) + + update_player_active(NAME_DS, view.current === DS) + update_player_active(NAME_VE, view.current === VE) + update_player_active(NAME_BK, view.current === BK) + + ui.this_card.className = make_card_class_name(view.deck[0]) + if (view.deck[1] > 0) { + ui.deck_outer.className = "card card_back" + ui.deck_size.textContent = `${view.deck[1]}` + } else { + ui.deck_outer.className = "hide" + } + + ui.this_card.classList.toggle("action", !!(view.actions && view.actions.event === 1)) + ui.shaded_event.classList.toggle("action", !!(view.actions && view.actions.shaded === 1)) + ui.unshaded_event.classList.toggle("action", !!(view.actions && view.actions.unshaded === 1)) + + layout_score() + +return + + layout_sop() + + layout_available(GOVT, TROOPS, 114, 248) + layout_available(GOVT, POLICE, 114, 448) + layout_available(FARC, GUERRILLA, 1396, 234) + layout_available(AUC, GUERRILLA, 196, 2370) + layout_available(CARTELS, GUERRILLA, 1465, 1970) + + for (let i = view.farc_zones.length; i < ui.farc_zones.length; ++i) + ui.farc_zones[i].className = "hide" + + let tix = 0 + + let list = [] + let bases = [] + let drugs = [] + for (let s = 0; s < data.spaces.length; ++s) { + let id = data.spaces[s].id + let xy + + if (s <= last_pop) { + switch (view.support[s]) { + case -2: ui.support[s].className = "token active_opposition"; break + case -1: ui.support[s].className = "token passive_opposition"; break + case 0: ui.support[s].className = "hide"; break + case 1: ui.support[s].className = "token passive_support"; break + case 2: ui.support[s].className = "token active_support"; break + } + } + + if (s >= first_loc && s <= last_loc) { + if (set_has(view.sabotage, s)) + ui.sabotage[s].className = "token sabotage" + else + ui.sabotage[s].className = "hide" + } + + if (s >= first_dept && s <= last_dept) { + ui.farc_zone[s].classList.toggle("hide", !(view.farc_zones & (1<<s))) + } + + if (s <= last_dept) { + if (view.govt_control & (1<<s)) + ui.control[s].className = "token govt_control" + else if (view.farc_control & (1<<s)) + ui.control[s].className = "token farc_control" + else + ui.control[s].className = "hide" + } + + tix = layout_terror(tix, s, map_get(view.terror, s, 0) * 1) + + update_rebels(BK, AMIR, view.rebel[BK]) + update_rebels(VE, RAJA, view.rebel[VE]) + + drugs.length = 0 + for (let i = 0; i < 4; ++i) { + let shx = view.shipments[i] + if (shx !== 0) { + if ((shx & 3) === 0 && view.pieces[(shx >> 2)] === s) + layout_shipments_push(drugs, ui.pieces[shx>>2], ui.shipments[i], piece_faction(shx>>2)) + else if ((shx & 3) !== 0 && (shx >> 2) === s) + layout_shipments_push(drugs, null, ui.shipments[i], shx & 3) + } + } + + if (s <= last_city) { + list.length = bases.length = 0 + filter_piece_list(list, s, FARC, GUERRILLA) + filter_piece_list(list, s, AUC, GUERRILLA) + filter_piece_list(list, s, CARTELS, GUERRILLA) + filter_piece_list(list, s, GOVT, TROOPS) + filter_piece_list(list, s, GOVT, POLICE) + filter_piece_list(bases, s, GOVT, BASE) + filter_piece_list(bases, s, FARC, BASE) + filter_piece_list(bases, s, AUC, BASE) + filter_piece_list(bases, s, CARTELS, BASE) + xy = get_layout_xy(s) + layout_pieces(list, xy[0], xy[1], null, null, s, 0) + layout_city_bases(bases, xy[0], xy[1] + get_layout_radius(s) - 12, s) + + layout_city_shipments(s, drugs, xy[0], xy[1]) + } else if (s <= last_dept) { + list.length = bases.length = 0 + filter_piece_list(list, s, FARC, GUERRILLA) + filter_piece_list(bases, s, FARC, BASE) + xy = get_layout_xy(s, "FARC") + layout_pieces(list, xy[0], xy[1], bases, drugs, s, FARC) + + list.length = bases.length = 0 + filter_piece_list(list, s, AUC, GUERRILLA) + filter_piece_list(bases, s, AUC, BASE) + xy = get_layout_xy(s, "AUC") + layout_pieces(list, xy[0], xy[1], bases, drugs, s, AUC) + + list.length = bases.length = 0 + filter_piece_list(list, s, CARTELS, GUERRILLA) + filter_piece_list(bases, s, CARTELS, BASE) + xy = get_layout_xy(s, "Cartels") + layout_pieces(list, xy[0], xy[1], bases, drugs, s, CARTELS) + + list.length = bases.length = 0 + filter_piece_list(list, s, GOVT, TROOPS) + filter_piece_list(list, s, GOVT, POLICE) + filter_piece_list(bases, s, GOVT, BASE) + xy = get_layout_xy(s, "Govt") + layout_pieces(list, xy[0], xy[1], bases, null, s, GOVT) + } else { + list.length = 0 + filter_piece_list(list, s, FARC, GUERRILLA) + filter_piece_list(list, s, AUC, GUERRILLA) + filter_piece_list(list, s, CARTELS, GUERRILLA) + xy = get_layout_xy(s, "INSURGENTS") + layout_pieces(list, xy[0], xy[1], null, s) + + list.length = 0 + filter_piece_list(list, s, GOVT, TROOPS) + filter_piece_list(list, s, GOVT, POLICE) + xy = get_layout_xy(s, "COIN") + layout_pieces(list, xy[0], xy[1], null, s) + + xy = get_layout_xy(s) + layout_loc_shipments(s, drugs, xy[0], xy[1]) + } + + ui.spaces[s].classList.toggle("action", is_action("space", s)) + ui.spaces[s].classList.toggle("selected", view.where === s) + } + + for (; tix < 40; ++tix) + ui.terror[tix].className = "hide" + + for (let i = first_piece[AUC][GUERRILLA]; i <= last_piece[AUC][GUERRILLA]; ++i) + ui.pieces[i].classList.toggle("hide", view.pieces[i] === OUT_OF_PLAY) + + list.length = 0 + for (let i = 0; i < 4; ++i) { + let shx = view.shipments[i] + let shf = shx & 3 + if (shx === 0) + list.push(ui.shipments[i]) + if (shf === 0) + ui.shipments[i].className = "token shipment" + else if (shf === FARC) + ui.shipments[i].className = "token shipment farc" + else if (shf === AUC) + ui.shipments[i].className = "token shipment auc" + else if (shf === CARTELS) + ui.shipments[i].className = "token shipment cartels" + if (view.actions && view.actions.shipment && set_has(view.actions.shipment, i)) + ui.shipments[i].classList.add("action") + if (view.selected_shipment === i) + ui.shipments[i].classList.add("selected") + } + layout_available_bases(list, 1532, 1722, 2, 2, 89, 69) + + list.length = 0 + filter_piece_list(list, AVAILABLE, GOVT, BASE) + layout_available_bases(list, 287 + 177, 371, 3, 1, 61, 0) + + list.length = 0 + filter_piece_list(list, AVAILABLE, FARC, BASE) + layout_available_bases(list, 446 + 543, 2295, 9, 1, 61, 0) + + list.length = 0 + filter_piece_list(list, AVAILABLE, AUC, BASE) + layout_available_bases(list, 446 + 360, 2386, 6, 1, 61, 0) + + list.length = 0 + filter_piece_list(list, AVAILABLE, CARTELS, BASE) + layout_available_bases(list, 1373 + 183, 2117, 3, 5, 63, 63) + + if (view.actions && view.actions.piece) + for (let i = 0; i < ui.pieces.length; ++i) + ui.pieces[i].classList.toggle("action", set_has(view.actions.piece, i)) + else + for (let i = 0; i < ui.pieces.length; ++i) + ui.pieces[i].classList.remove("action") + for (let i = 0; i < ui.pieces.length; ++i) + ui.pieces[i].classList.toggle("selected", view.who === i) + + action_menu(document.getElementById("negotiate_menu"), [ + "remove_pieces", + "transfer_resources", + "transfer_shipment", + "ask_resources", + "ask_shipment", + ]) + + // Select Faction + action_button("govt", "Government") + action_button("farc", "FARC") + action_button("auc", "AUC") + action_button("cartels", "Cartels") + + confirm_action_button("choose_govt", "Government", "Choose GOVERNMENT to execute this event?") + confirm_action_button("choose_farc", "FARC", "Choose FARC to execute this event?") + confirm_action_button("choose_auc", "AUC", "Choose AUC to execute this event?") + confirm_action_button("choose_cartels", "Cartels", "Choose CARTELS to execute this event?") + + // Select Operation + action_button("train", "Train") + action_button("patrol", "Patrol") + action_button("sweep", "Sweep") + action_button("assault", "Assault") + action_button("rally", "Rally") + action_button("march", "March") + action_button("attack", "Attack") + action_button("terror", "Terror") + + // Select Special Activity + action_button("air_lift", "Air Lift") + action_button("air_strike", "Air Strike") + action_button("eradicate", "Eradicate") + action_button("extort", "Extort") + action_button("ambush", "Ambush") + action_button("assassinate", "Assassinate") + action_button("kidnap", "Kidnap") + action_button("cultivate", "Cultivate") + action_button("process", "Process") + action_button("bribe", "Bribe") + + // Train/Rally sub-actions + action_button("move", "Move") + action_button("flip", "Flip") + action_button("base", "Base") + action_button("civic", "Civic Action") + + action_button("support", "Support") + action_button("opposition", "Opposition") + + action_button("remove", "Remove") + action_button("roll", "Roll") + action_button("skip", "Skip") + action_button("next", "Next") + action_button("pass", "Pass") + + action_button("end_train", "End Train") + action_button("end_patrol", "End Patrol") + action_button("end_sweep", "End Sweep") + action_button("end_assault", "End Assault") + action_button("end_rally", "End Rally") + action_button("end_march", "End March") + action_button("end_attack", "End Attack") + action_button("end_terror", "End Terror") + + action_button("end_air_lift", "End Air Lift") + action_button("end_extort", "End Extort") + action_button("end_assassinate", "End Assassinate") + action_button("end_kidnap", "End Kidnap") + action_button("end_process", "End Process") + action_button("end_bribe", "End Bribe") + + action_button("end_event", "End Event") + + action_button("deny", "Deny") + action_button("done", "Done") + action_button("undo", "Undo") +} + +/* TOOLTIPS */ + +function register_card_tip(e, c) { + e.onmouseenter = () => on_focus_card_tip(c) + e.onmouseleave = on_blur_card_tip +} + +function on_focus_this_event() { + let c = view.deck[0] + if (c > 0) + ui.status.textContent = data.card_title[c] +} + +function on_focus_unshaded_event() { + let c = view.deck[0] + if (c > 0) { + let f = data.card_flavor[c] + if (f) + ui.status.textContent = data.card_title[c] + " - " + f + else + ui.status.textContent = data.card_title[c] + } +} + +function on_focus_shaded_event() { + let c = view.deck[0] + if (c > 0) { + ui.status.textContent = data.card_title[c] + " - " + data.card_flavor_shaded[c] + } +} + +function on_blur_event() { + ui.status.textContent = "" +} + +function on_focus_card_tip(c) { + ui.card_tip.className = "card card_" + c +} + +function on_blur_card_tip() { + ui.card_tip.className = "hide" +} + +function on_focus_space_tip(s) { + ui.spaces[s].classList.add("tip") +} + +function on_blur_space_tip(s) { + ui.spaces[s].classList.remove("tip") +} + +function on_click_space_tip(s) { + scroll_into_view(ui.spaces[s]) +} + +/* LOG */ + +function sub_card(match, p1) { + let x = p1 | 0 + let n = data.card_title[x] + return `<span class="tip" onmouseenter="on_focus_card_tip(${x})" onmouseleave="on_blur_card_tip()">${n}</span>` +} + +function sub_space(match, p1) { + let x = p1 | 0 + let n = data.space_name[x] + return `<span class="tip" onmouseenter="on_focus_space_tip(${x})" onmouseleave="on_blur_space_tip(${x})" onmousedown="on_click_space_tip(${x})">${n}</span>` +} + +function on_log(text) { + let p = document.createElement("div") + + if (text.match(/^>/)) { + text = text.substring(1) + p.className = "indent" + } + + text = text.replace(/&/g, "&") + text = text.replace(/</g, "<") + text = text.replace(/>/g, ">") + + if (text.match(/^\.h1/)) { + text = text.substring(4) + p.className = "h1" + } + else if (text.match(/^\.h2 Gov/)) { + text = text.substring(3) + p.className = "h2 govt" + } + else if (text.match(/^\.h2 AUC/)) { + text = text.substring(3) + p.className = "h2 auc" + } + else if (text.match(/^\.h2 Cartels/)) { + text = text.substring(3) + p.className = "h2 cartels" + } + else if (text.match(/^\.h2 FARC/)) { + text = text.substring(3) + p.className = "h2 farc" + } + else if (text.match(/^\.h2 /)) { + text = text.substring(3) + p.className = "h2" + } + else if (text.match(/^\.h3/)) { + text = text.substring(4) + p.className = "h3" + } + else if (text.match(/^\.h4/)) { + text = text.substring(4) + p.className = "h4" + } + else if (text.match(/^\.n/)) { + text = text.substring(3) + p.className = "italic" + } + else if (text.match(/^\.i/)) { + text = text.substring(3) + p.className = "indent italic" + } + + text = text.replace(/C(\d+)/g, sub_card) + text = text.replace(/S(\d+)/g, sub_space) + + p.innerHTML = text + return p +} |