summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-01-06 12:35:52 +0100
committerTor Andersson <tor@ccxvii.net>2022-11-16 19:08:56 +0100
commite6cbdd5c77a4ec4b771fdec2094a480ff6d17eb4 (patch)
tree61197d2cfb7fac230d8a4f5092db12900aa0dc2e
parenta2dd2ed3edd350a03fa75723184cadc70eca798e (diff)
downloadjulius-caesar-e6cbdd5c77a4ec4b771fdec2094a480ff6d17eb4.tar.gz
Update for new server version.
-rw-r--r--play.css6
-rw-r--r--play.html12
-rw-r--r--play.js581
-rw-r--r--rules.js47
4 files changed, 265 insertions, 381 deletions
diff --git a/play.css b/play.css
index 3ae1280..a81f79b 100644
--- a/play.css
+++ b/play.css
@@ -4,8 +4,8 @@ main { background-color: #461145; }
#roles { background-color: tan; }
header { background-color: tan; }
header.your_turn { background-color: orange; }
-.one .role_name { background-color: salmon; }
-.two .role_name { background-color: #eb5; }
+#role_Caesar .role_name { background-color: salmon; }
+#role_Pompeius .role_name { background-color: #eb5; }
#turn_info { background-color: burlywood; }
#log { background-color: wheat; }
@@ -82,7 +82,7 @@ header.your_turn { background-color: orange; }
#battle_header { background-color: brown; color: lemonchiffon; }
.battle_separator { background-color: brown; }
-.battle_line.enemy .battle_menu_list { min-height: 0; }
+body:not(.replay) .battle_line.enemy .battle_menu_list { min-height: 0; }
.battle_reserves .battle_menu_list { min-height: 0; }
.battle_reserves > td > div { height: 75px; padding: 5px; }
.battle_a_cell > div { min-width: 90px; padding: 5px 5px; }
diff --git a/play.html b/play.html
index bd37f2f..5bf970f 100644
--- a/play.html
+++ b/play.html
@@ -6,13 +6,12 @@
<title>JULIUS CAESAR</title>
<link rel="icon" href="Vexilloid_of_the_Roman_Empire.svg">
<link rel="stylesheet" href="/fonts/fonts.css">
-<link rel="stylesheet" href="/common/grid.css">
-<link rel="stylesheet" href="/common/battle_abc.css">
+<link rel="stylesheet" href="/common/play.css">
+<link rel="stylesheet" href="/common/columbia.css">
<link rel="stylesheet" href="blocks_simple.css">
<link rel="stylesheet" href="blocks_columbia.css">
<link rel="stylesheet" href="play.css">
-<script defer src="/socket.io/socket.io.min.js"></script>
-<script defer src="/common/client.js"></script>
+<script defer src="/common/play.js"></script>
<script defer src="data.js"></script>
<script defer src="play.js"></script>
</head>
@@ -69,7 +68,7 @@
<aside>
<div id="roles">
- <div class="role one">
+ <div class="role" id="role_Caesar">
<div class="role_name">
Caesar
<div class="role_vp" id="caesar_vp">VP</div>
@@ -77,7 +76,7 @@
</div>
<div class="role_info"><div class="show card card_back" id="caesar_card"></div></div>
</div>
- <div class="role two">
+ <div class="role" id="role_Pompeius">
<div class="role_name">
Pompeius
<div class="role_vp" id="pompeius_vp">VP</div>
@@ -93,6 +92,7 @@
<main>
<div id="mapwrap">
<div id="map">
+ <div id="offmap" style="visibility:hidden"></div>
<div id="blocks"></div>
<div id="spaces"></div>
<div id="turn" class="year_705"></div>
diff --git a/play.js b/play.js
index 52545f8..0fb4411 100644
--- a/play.js
+++ b/play.js
@@ -57,22 +57,15 @@ const step_up_animation = [
];
let ui = {
- spaces: {},
- known: {},
- secret: {
- Caesar: { offmap: [] },
- Pompeius: { offmap: [] },
- Cleopatra: { offmap: [] },
- },
- seen: new Set(),
- present: new Set(),
- battle_block: {},
- battle_menu: {},
- map_steps: {},
- map_location: {},
- battle_steps: {},
cards: {},
card_backs: {},
+ spaces: {},
+ blocks: {},
+ battle_menu: {},
+ battle_block: {},
+ old_steps: null,
+ old_location: null,
+ present: new Set(),
};
create_log_entry = function (text) {
@@ -104,34 +97,47 @@ create_log_entry = function (text) {
return p;
}
-const STEPS = [ 0, "I", "II", "III", "IIII" ];
+function on_focus_space(evt) {
+ document.getElementById("status").textContent = evt.target.space;
+}
-function block_description(b) {
- let s = ui.map_steps[b] || ui.battle_steps[b];
- let c = BLOCKS[b].initiative + BLOCKS[b].firepower;
- let levy = BLOCKS[b].levy;
- if (levy)
- return BLOCKS[b].name + " (" + levy + ") " + STEPS[s] + "-" + c;
- return BLOCKS[b].name + " " + STEPS[s] + "-" + c;
+function on_blur_space(evt) {
+ document.getElementById("status").textContent = "";
}
-function block_name(b) {
- return BLOCKS[b].name;
+function on_click_space(evt) {
+ send_action('space', evt.target.space);
}
-function on_focus_space(evt) {
- document.getElementById("status").textContent = evt.target.space;
+const STEPS = [ 0, "I", "II", "III", "IIII" ];
+
+function block_description(b) {
+ if (is_known_block(b)) {
+ let s = BLOCKS[b].steps;
+ let c = BLOCKS[b].initiative + BLOCKS[b].firepower;
+ let levy = BLOCKS[b].levy;
+ if (levy)
+ return BLOCKS[b].name + " (" + levy + ") " + STEPS[s] + "-" + c;
+ return BLOCKS[b].name + " " + STEPS[s] + "-" + c;
+ }
+ return block_owner(b);
}
-function on_blur_space(evt) {
- document.getElementById("status").textContent = "";
+function block_owner(who) {
+ if (who in view.owner)
+ return view.owner[who];
+ return BLOCKS[who].owner;
}
-function on_focus_block(evt) {
+function block_name(b) {
+ return BLOCKS[b].name;
+}
+
+function on_focus_map_block(evt) {
document.getElementById("status").textContent = block_description(evt.target.block);
}
-function on_blur_block(evt) {
+function on_blur_map_block(evt) {
document.getElementById("status").textContent = "";
}
@@ -141,11 +147,11 @@ function on_focus_battle_block(evt) {
if (!evt.target.classList.contains("known"))
document.getElementById("status").textContent = "Reserves";
- if (game.actions && game.actions.battle_fire && game.actions.battle_fire.includes(b))
+ if (view.actions && view.actions.battle_fire && view.actions.battle_fire.includes(b))
msg = "Fire with " + msg;
- else if (game.actions && game.actions.battle_retreat && game.actions.battle_retreat.includes(b))
+ else if (view.actions && view.actions.battle_retreat && view.actions.battle_retreat.includes(b))
msg = "Retreat with " + msg;
- else if (game.actions && game.actions.battle_hit && game.actions.battle_hit.includes(b))
+ else if (view.actions && view.actions.battle_hit && view.actions.battle_hit.includes(b))
msg = "Take hit on " + msg;
document.getElementById("status").textContent = msg;
@@ -159,27 +165,54 @@ function on_focus_battle_fire(evt) {
document.getElementById("status").textContent =
"Fire with " + block_name(evt.target.block);
}
+
function on_focus_battle_retreat(evt) {
document.getElementById("status").textContent =
"Retreat with " + block_name(evt.target.block);
}
+
function on_focus_battle_pass(evt) {
document.getElementById("status").textContent =
"Pass with " + block_name(evt.target.block);
}
+
function on_focus_battle_hit(evt) {
document.getElementById("status").textContent =
"Take hit on " + block_name(evt.target.block);
}
+
function on_blur_battle_button(evt) {
document.getElementById("status").textContent = "";
}
+function on_click_battle_block(evt) { send_action('block', evt.target.block); }
+function on_click_battle_hit(evt) { send_action('battle_hit', evt.target.block); }
+function on_click_battle_fire(evt) { send_action('battle_fire', evt.target.block); }
+function on_click_battle_retreat(evt) { send_action('battle_retreat', evt.target.block); }
+
+function on_click_battle_pass(evt) {
+ if (window.confirm("Are you sure that you want to PASS with " + block_name(evt.target.block) + "?"))
+ send_action('battle_pass', evt.target.block);
+}
+
+function on_click_map_block(evt) {
+ let b = evt.target.block;
+ let s = view.location[b];
+ if (view.actions && view.actions.secret && view.actions.secret.includes(s))
+ send_action('secret', [s, BLOCKS[b].color]);
+ else if (!view.battle)
+ send_action('block', b);
+}
+
function build_map() {
// These must match up with the sizes in play.html
const city_size = 60+10;
const sea_size = 70+10;
+ ui.blocks_element = document.getElementById("blocks");
+ ui.offmap_element = document.getElementById("offmap");
+ ui.spaces_element = document.getElementById("spaces");
+
for (let s in SPACES) {
let space = SPACES[s];
let element = document.createElement("div");
@@ -192,45 +225,26 @@ function build_map() {
element.setAttribute("draggable", "false");
element.addEventListener("mouseenter", on_focus_space);
element.addEventListener("mouseleave", on_blur_space);
- element.addEventListener("click", select_space);
+ element.addEventListener("click", on_click_space);
element.style.left = (space.x - size/2) + "px";
element.style.top = (space.y - size/2) + "px";
if (space.type !== 'pool')
document.getElementById("spaces").appendChild(element);
element.space = s;
ui.spaces[s] = element;
-
- ui.secret[CLEOPATRA][s] = [];
- ui.secret[CAESAR][s] = [];
- ui.secret[POMPEIUS][s] = [];
}
- function build_known_block(b, block, color) {
+ function build_map_block(b, block) {
let element = document.createElement("div");
element.classList.add("block");
element.classList.add("known");
- element.classList.add(color);
+ element.classList.add(block.color);
element.classList.add("block_"+block.label);
- element.addEventListener("mouseenter", on_focus_block);
- element.addEventListener("mouseleave", on_blur_block);
+ element.addEventListener("mouseenter", on_focus_map_block);
+ element.addEventListener("mouseleave", on_blur_map_block);
element.addEventListener("click", on_click_map_block);
- document.getElementById("blocks").appendChild(element);
- element.style.visibility = 'hidden';
element.block = b;
- ui.known[b] = element;
- }
-
- function build_secret_block(b, block, color) {
- let element = document.createElement("div");
- element.secret_index = ui.secret[color].offmap.length;
- element.classList.add("block");
- element.classList.add("secret");
- element.classList.add(color);
- element.addEventListener("click", select_secret_block);
- document.getElementById("blocks").appendChild(element);
- element.style.visibility = 'hidden';
- element.owner = BLOCKS[b].owner;
- ui.secret[color].offmap.unshift(element);
+ ui.blocks[b] = element;
}
function build_battle_button(menu, b, c, click, enter, img_src) {
@@ -246,11 +260,10 @@ function build_map() {
menu.appendChild(img);
}
- function build_battle_block(b, block, color) {
+ function build_battle_block(b, block) {
let element = document.createElement("div");
element.classList.add("block");
- element.classList.add("known");
- element.classList.add(color);
+ element.classList.add(block.color);
element.classList.add("block_"+block.label);
element.addEventListener("mouseenter", on_focus_battle_block);
element.addEventListener("mouseleave", on_blur_battle_block);
@@ -262,16 +275,16 @@ function build_map() {
action_list.classList.add("battle_menu_list");
action_list.appendChild(element);
build_battle_button(action_list, b, "hit",
- select_battle_hit, on_focus_battle_hit,
+ on_click_battle_hit, on_focus_battle_hit,
"/images/cross-mark.svg");
build_battle_button(action_list, b, "fire",
- select_battle_fire, on_focus_battle_fire,
+ on_click_battle_fire, on_focus_battle_fire,
"/images/pointy-sword.svg");
build_battle_button(action_list, b, "retreat",
- select_battle_retreat, on_focus_battle_retreat,
+ on_click_battle_retreat, on_focus_battle_retreat,
"/images/flying-flag.svg");
build_battle_button(action_list, b, "pass",
- select_battle_pass, on_focus_battle_pass,
+ on_click_battle_pass, on_focus_battle_pass,
"/images/sands-of-time.svg");
let menu = document.createElement("div");
@@ -283,10 +296,9 @@ function build_map() {
for (let b in BLOCKS) {
let block = BLOCKS[b];
- let color = (block.name === "Cleopatra" ? "Cleopatra" : block.owner);
- build_known_block(b, block, color);
- build_secret_block(b, block, color);
- build_battle_block(b, block, color);
+ block.color = (block.name === "Cleopatra" ? "Cleopatra" : block.owner);
+ build_map_block(b, block);
+ build_battle_block(b, block);
}
for (let c = 1; c <= 27; ++c)
@@ -295,9 +307,11 @@ function build_map() {
ui.card_backs[c] = document.getElementById("back+" + c);
}
-function update_steps(memo, block, steps, element, animate) {
- let old_steps = memo[block] || steps;
- memo[block] = steps;
+function update_steps(block, element, animate) {
+ let old_steps = ui.old_steps[block] || view.steps[block];
+ let steps = view.steps[block];
+ if (view.location[block] !== ui.old_location[block])
+ animate = false;
if (label_style === 'simple' && steps !== old_steps && animate) {
let options = { duration: 700, easing: 'ease', iterations: Math.abs(steps-old_steps) }
@@ -314,17 +328,17 @@ function update_steps(memo, block, steps, element, animate) {
element.classList.add("r"+(BLOCKS[block].steps - steps));
}
-function layout_blocks(location, secret, known) {
+function layout_blocks(location, north, south) {
if (label_layout === 'spread' || (location === LEVY || location === DEAD))
- layout_blocks_spread(location, secret, known);
+ layout_blocks_spread(location, north, south);
else
- layout_blocks_stacked(location, secret, known);
+ layout_blocks_stacked(location, north, south);
}
-function layout_blocks_spread(location, secret, known) {
+function layout_blocks_spread(location, north, south) {
let wrap = SPACES[location].wrap;
- let s = secret.length;
- let k = known.length;
+ let s = north.length;
+ let k = south.length;
let n = s + k;
let row, rows = [];
let i = 0;
@@ -336,21 +350,21 @@ function layout_blocks_spread(location, secret, known) {
new_line();
- while (secret.length > 0) {
+ while (north.length > 0) {
if (i === wrap)
new_line();
- row.push(secret.shift());
+ row.push(north.shift());
++i;
}
- // Break early if secret and known fit in exactly two rows and more than two blocks.
+ // Break early if north and south fit in exactly two rows and more than two blocks.
if (s > 0 && s <= wrap && k > 0 && k <= wrap && n > 2)
new_line();
- while (known.length > 0) {
+ while (south.length > 0) {
if (i === wrap)
new_line();
- row.push(known.shift());
+ row.push(south.shift());
++i;
}
@@ -391,152 +405,99 @@ function position_block_spread(location, row, n_rows, col, n_cols, element) {
function layout_blocks_stacked(location, secret, known) {
let s = secret.length;
let k = known.length;
- let n = s + k;
+ let both = secret.length > 0 && known.length > 0;
let i = 0;
while (secret.length > 0)
- position_block_stacked(location, i++, n, secret.shift());
+ position_block_stacked(location, i++, (s-1)/2, both ? 1 : 0, secret.shift());
+ i = 0;
while (known.length > 0)
- position_block_stacked(location, i++, n, known.shift());
+ position_block_stacked(location, i++, (k-1)/2, 0, known.shift());
}
-function position_block_stacked(location, i, n, element) {
+function position_block_stacked(location, i, c, k, element) {
let space = SPACES[location];
let block_size = (label_style === 'columbia') ? 56+6 : 48+4;
- let x = space.x - block_size/2 - (n-1) * 9 + i * 18;
- let y = space.y - block_size/2 - (n-1) * 9 + i * 18;
- element.style.left = x+"px";
- element.style.top = y+"px";
+ let x = space.x + (i - c) * 16 + k * 12;
+ let y = space.y + (i - c) * 16 - k * 12;
+ element.style.left = ((x - block_size/2)|0)+"px";
+ element.style.top = ((y - block_size/2)|0)+"px";
}
-function sort_secret(a,b) {
- return a.secret_index - b.secret_index;
+function show_block(element) {
+ if (element.parentElement !== ui.blocks_element)
+ ui.blocks_element.appendChild(element);
}
-function update_map() {
- let overflow = { Caesar: [], Pompeius: [], Cleopatra: [] };
- let layout = {};
-
- for (let s in SPACES)
- layout[s] = { Caesar: [], Pompeius: [] };
-
- // Move secret blocks to overflow queue if there are too many in a location
- for (let s in SPACES) {
- for (let color of [CAESAR, POMPEIUS, CLEOPATRA]) {
- let max = 0;
- if (game.secret[color] && game.secret[color][s])
- max = game.secret[color][s].length;
- while (ui.secret[color][s].length > max)
- overflow[color].push(ui.secret[color][s].pop());
- }
- }
+function hide_block(element) {
+ if (element.parentElement !== ui.offmap_element)
+ ui.offmap_element.appendChild(element);
+}
- // Add secret blocks if there are too few in a location
- for (let s in SPACES) {
- for (let color of [CAESAR, POMPEIUS, CLEOPATRA]) {
- let max = 0;
- if (game.secret[color] && game.secret[color][s])
- max = game.secret[color][s].length;
- while (ui.secret[color][s].length < max) {
- if (overflow[color].length > 0) {
- ui.secret[color][s].push(overflow[color].pop());
- } else {
- let element = ui.secret[color].offmap.pop();
- element.style.visibility = 'visible';
- ui.secret[color][s].push(element);
- }
- }
- }
- }
+function is_known_block(who) {
+ if (view.game_over)
+ return true;
+ if (block_owner(who) === player)
+ return true;
+ let where = view.location[who];
+ if (where === DEAD)
+ return true;
+ return false;
+}
- // Remove any blocks left in the overflow queue
- for (let color of [CAESAR, POMPEIUS, CLEOPATRA]) {
- while (overflow[color].length > 0) {
- let element = overflow[color].pop();
- element.style.visibility = 'hidden';
- // Prevent move animation when blocks are revived.
- element.style.left = null;
- element.style.top = null;
- ui.secret[color].offmap.push(element);
- }
- }
+function is_visible_block(where, who) {
+ if (view.game_over)
+ return true;
+ if (where === "Levy")
+ return block_owner(who) === player;
+ return true;
+}
- // Hide formerly known blocks
- for (let b in BLOCKS) {
- if (!(b in game.known)) {
- ui.known[b].style.visibility = 'hidden';
- // Prevent move animation when blocks are revived.
- ui.known[b].style.left = null;
- ui.known[b].style.top = null;
- }
- }
+function update_map() {
+ let layout = {};
- // Add secret blocks to layout
- for (let color in game.secret) {
- for (let location in game.secret[color]) {
- let i = 0;
- for (let [moved, jupiter] of game.secret[color][location]) {
- let element = ui.secret[color][location][i++];
- if (moved)
- element.classList.add('moved');
- else
- element.classList.remove('moved');
- if (jupiter)
- element.classList.add('jupiter');
- else
- element.classList.remove('jupiter');
- if (color === game.mars && location === game.surprise)
- element.classList.add("mars");
- else
- element.classList.remove("mars");
- if (color === game.neptune && location === game.surprise)
- element.classList.add("neptune");
- else
- element.classList.remove("neptune");
- let owner = color;
- if (owner === CLEOPATRA)
- owner = POMPEIUS;
- if (jupiter)
- owner = ENEMY[owner];
- layout[location][owner].push(element);
- element.style.visibility = 'visible';
+ for (let s in SPACES)
+ layout[s] = { north: [], south: [] };
+
+ for (let b in view.location) {
+ let info = BLOCKS[b];
+ let element = ui.blocks[b];
+ let space = view.location[b];
+ if (is_visible_block(space, b)) {
+ let moved = view.moved[b] ? " moved" : "";
+ if (space === DEAD && info.type !== 'leader')
+ moved = " moved";
+ if (is_known_block(b)) {
+ let image = " block_" + info.label;
+ let known = " known";
+ let jupiter = "";
+ if (block_owner(b) !== BLOCKS[b].owner && view.game_over)
+ jupiter = " jupiter";
+ element.classList = info.color + known + " block" + image + moved + jupiter;
+ update_steps(b, element, true);
+ } else {
+ let jupiter = "";
+ let mars = "";
+ let neptune = "";
+ if (block_owner(b) !== BLOCKS[b].owner)
+ jupiter = " jupiter";
+ if (block_owner(b) === view.mars && space === view.surprise)
+ mars = " mars";
+ if (block_owner(b) === view.neptune && space === view.surprise)
+ neptune = " neptune";
+ element.classList = info.color + " block" + moved + jupiter + mars + neptune;
}
+ if (block_owner(b) === CAESAR)
+ layout[space].north.push(element);
+ else
+ layout[space].south.push(element);
+ show_block(element);
+ } else {
+ hide_block(element);
}
}
- // Add known blocks to layout
- for (let block in game.known) {
- let element = ui.known[block];
- let location = game.known[block][0];
- let steps = game.known[block][1];
- let moved = game.known[block][2];
- let jupiter = game.known[block][3];
- let color = BLOCKS[block].owner;
- if (jupiter)
- color = ENEMY[color];
-
- element.style.visibility = 'visible';
-
- layout[location][color].push(element);
-
- let old_location = ui.map_location[block];
- update_steps(ui.map_steps, block, steps, element, location === old_location);
- ui.map_location[block] = location;
-
- if (moved || (location === DEAD && BLOCKS[block].type !== 'leader'))
- element.classList.add("moved");
- else
- element.classList.remove("moved");
- if (jupiter)
- element.classList.add("jupiter");
- else
- element.classList.remove("jupiter");
-
- ui.seen.add(block);
- }
-
- // Layout blocks on map
- for (let location in SPACES)
- layout_blocks(location, layout[location].Caesar, layout[location].Pompeius);
+ for (let space in SPACES)
+ layout_blocks(space, layout[space].north, layout[space].south);
// Mark selections and highlights
@@ -546,34 +507,26 @@ function update_map() {
ui.spaces[where].classList.remove('where');
}
}
- if (game.actions && game.actions.space)
- for (let where of game.actions.space)
+ if (view.actions && view.actions.space)
+ for (let where of view.actions.space)
ui.spaces[where].classList.add('highlight');
- if (game.where)
- ui.spaces[game.where].classList.add('where');
for (let b in BLOCKS) {
- ui.known[b].classList.remove('highlight');
- ui.known[b].classList.remove('selected');
+ ui.blocks[b].classList.remove('highlight');
+ ui.blocks[b].classList.remove('selected');
}
- if (!game.battle) {
- if (game.actions && game.actions.block)
- for (let b of game.actions.block)
- ui.known[b].classList.add('highlight');
- if (game.who)
- ui.known[game.who].classList.add('selected');
+ if (!view.battle) {
+ if (view.actions && view.actions.block)
+ for (let b of view.actions.block)
+ ui.blocks[b].classList.add('highlight');
+ if (view.who)
+ ui.blocks[view.who].classList.add('selected');
}
- for (let o in ui.secret) {
- for (let s in ui.secret[o]) {
- if (game.actions && game.actions.secret && game.actions.secret.includes(s)) {
- for (let e of ui.secret[o][s])
- e.classList.add("highlight");
- } else {
- for (let e of ui.secret[o][s])
- e.classList.remove("highlight");
- }
- }
+ for (let b in BLOCKS) {
+ let s = view.location[b];
+ if (view.actions && view.actions.secret && view.actions.secret.includes(s))
+ ui.blocks[b].classList.add('highlight');
}
}
@@ -583,11 +536,10 @@ function update_battle() {
ui.present.clear();
- for (let [block, steps, moved] of list) {
- ui.seen.add(block);
+ for (let block of list) {
ui.present.add(block);
- if (block === game.who)
+ if (block === view.who)
ui.battle_menu[block].classList.add("selected");
else
ui.battle_menu[block].classList.remove("selected");
@@ -598,23 +550,23 @@ function update_battle() {
ui.battle_menu[block].classList.remove('retreat');
ui.battle_menu[block].classList.remove('pass');
- if (game.actions && game.actions.block && game.actions.block.includes(block))
+ if (view.actions && view.actions.block && view.actions.block.includes(block))
ui.battle_block[block].classList.add("highlight");
- if (game.actions && game.actions.battle_fire && game.actions.battle_fire.includes(block))
+ if (view.actions && view.actions.battle_fire && view.actions.battle_fire.includes(block))
ui.battle_menu[block].classList.add('fire');
- if (game.actions && game.actions.battle_retreat && game.actions.battle_retreat.includes(block))
+ if (view.actions && view.actions.battle_retreat && view.actions.battle_retreat.includes(block))
ui.battle_menu[block].classList.add('retreat');
- if (game.actions && game.actions.battle_pass && game.actions.battle_pass.includes(block))
+ if (view.actions && view.actions.battle_pass && view.actions.battle_pass.includes(block))
ui.battle_menu[block].classList.add('pass');
- if (game.actions && game.actions.battle_hit && game.actions.battle_hit.includes(block))
+ if (view.actions && view.actions.battle_hit && view.actions.battle_hit.includes(block))
ui.battle_menu[block].classList.add('hit');
- update_steps(ui.battle_steps, block, steps, ui.battle_block[block], true);
+ update_steps(block, ui.battle_block[block], true);
if (reserve)
ui.battle_block[block].classList.add("secret");
else
ui.battle_block[block].classList.remove("secret");
- if (moved || reserve)
+ if (view.moved[block] || reserve)
ui.battle_block[block].classList.add("moved");
else
ui.battle_block[block].classList.remove("moved");
@@ -636,27 +588,27 @@ function update_battle() {
}
if (player === CAESAR) {
- fill_cell("FR", game.battle.CR, true);
- fill_cell("FA", game.battle.CA, false);
- fill_cell("FB", game.battle.CB, false);
- fill_cell("FC", game.battle.CC, false);
- fill_cell("FD", game.battle.CD, false);
- fill_cell("EA", game.battle.PA, false);
- fill_cell("EB", game.battle.PB, false);
- fill_cell("EC", game.battle.PC, false);
- fill_cell("ED", game.battle.PD, false);
- fill_cell("ER", game.battle.PR, true);
+ fill_cell("FR", view.battle.CR, true);
+ fill_cell("FA", view.battle.CA, false);
+ fill_cell("FB", view.battle.CB, false);
+ fill_cell("FC", view.battle.CC, false);
+ fill_cell("FD", view.battle.CD, false);
+ fill_cell("EA", view.battle.PA, false);
+ fill_cell("EB", view.battle.PB, false);
+ fill_cell("EC", view.battle.PC, false);
+ fill_cell("ED", view.battle.PD, false);
+ fill_cell("ER", view.battle.PR, true);
} else {
- fill_cell("ER", game.battle.CR, true);
- fill_cell("EA", game.battle.CA, false);
- fill_cell("EB", game.battle.CB, false);
- fill_cell("EC", game.battle.CC, false);
- fill_cell("ED", game.battle.CD, false);
- fill_cell("FA", game.battle.PA, false);
- fill_cell("FB", game.battle.PB, false);
- fill_cell("FC", game.battle.PC, false);
- fill_cell("FD", game.battle.PD, false);
- fill_cell("FR", game.battle.PR, true);
+ fill_cell("ER", view.battle.CR, true);
+ fill_cell("EA", view.battle.CA, false);
+ fill_cell("EB", view.battle.CB, false);
+ fill_cell("EC", view.battle.CC, false);
+ fill_cell("ED", view.battle.CD, false);
+ fill_cell("FA", view.battle.PA, false);
+ fill_cell("FB", view.battle.PB, false);
+ fill_cell("FC", view.battle.PC, false);
+ fill_cell("FD", view.battle.PD, false);
+ fill_cell("FR", view.battle.PR, true);
}
}
@@ -671,15 +623,15 @@ function update_card_display(element, card, prior_card) {
}
function update_cards() {
- update_card_display(document.getElementById("caesar_card"), game.c_card, game.prior_c_card);
- update_card_display(document.getElementById("pompeius_card"), game.p_card, game.prior_p_card);
+ update_card_display(document.getElementById("caesar_card"), view.c_card, view.prior_c_card);
+ update_card_display(document.getElementById("pompeius_card"), view.p_card, view.prior_p_card);
for (let c = 1; c <= 27; ++c) {
let element = ui.cards[c];
- if (game.hand.includes(c)) {
+ if (view.hand.includes(c)) {
element.classList.add("show");
- if (game.actions && game.actions.card) {
- if (game.actions.card.includes(c)) {
+ if (view.actions && view.actions.card) {
+ if (view.actions.card.includes(c)) {
element.classList.add("enabled");
element.classList.remove("disabled");
} else {
@@ -695,100 +647,52 @@ function update_cards() {
}
}
- if (player === 'Observer') {
- let n = game.hand.length;
- for (let c = 1; c <= 6; ++c)
- if (c <= n)
- ui.card_backs[c].classList.add("show");
- else
- ui.card_backs[c].classList.remove("show");
- }
+ let n = view.hand.length;
+ for (let c = 1; c <= 6; ++c)
+ if (c <= n && player === 'Observer')
+ ui.card_backs[c].classList.add("show");
+ else
+ ui.card_backs[c].classList.remove("show");
}
function on_update() {
- document.getElementById("turn").className = "year_" + game.year;
- document.getElementById("caesar_vp").textContent = game.c_vp + " VP";
- document.getElementById("pompeius_vp").textContent = game.p_vp + " VP";
- if (game.turn < 1)
- document.getElementById("turn_info").textContent = `Year ${game.year}`;
+ if (!ui.old_steps) {
+ ui.old_steps = view.steps;
+ ui.old_location = view.location;
+ }
+
+ document.getElementById("turn").className = "year_" + view.year;
+ document.getElementById("caesar_vp").textContent = view.c_vp + " VP";
+ document.getElementById("pompeius_vp").textContent = view.p_vp + " VP";
+ if (view.turn < 1)
+ document.getElementById("turn_info").textContent = `Year ${view.year}`;
else
- document.getElementById("turn_info").textContent = `Turn ${game.turn} of Year ${game.year}`;
+ document.getElementById("turn_info").textContent = `Turn ${view.turn} of Year ${view.year}`;
action_button("surprise", "Surprise!");
action_button("pass");
action_button("undo", "Undo");
- ui.seen.clear();
-
update_cards();
update_map();
- for (let b in BLOCKS)
- if (!ui.seen.has(b))
- ui.map_steps[b] = 0;
-
- ui.seen.clear();
-
- if (game.battle) {
- document.getElementById("battle_header").textContent = game.battle.title;
- document.getElementById("battle_message").textContent = game.battle.flash;
+ if (view.battle) {
+ document.getElementById("battle_header").textContent = view.battle.title;
+ document.getElementById("battle_message").textContent = view.battle.flash;
document.getElementById("battle").classList.add("show");
update_battle();
} else {
document.getElementById("battle").classList.remove("show");
}
- for (let b in BLOCKS)
- if (!ui.seen.has(b))
- ui.battle_steps[b] = 0;
+ ui.old_location = Object.assign({}, view.location);
+ ui.old_steps = Object.assign({}, view.steps);
}
function select_card(c) {
send_action('card', c);
}
-function select_space(evt) {
- send_action('space', evt.target.space);
-}
-
-function on_click_battle_block(evt) {
- send_action('block', evt.target.block);
-}
-
-function on_click_map_block(evt) {
- if (!game.battle)
- send_action('block', evt.target.block);
-}
-
-function select_secret_block(evt) {
- let element = evt.target;
- let owner = null;
- let where = null;
- for (let o in ui.secret) {
- for (let s in ui.secret[o]) {
- if (ui.secret[o][s].includes(element)) {
- owner = o;
- where = s;
- break;
- }
- }
- }
- if (game.actions && game.actions.secret && game.actions.secret.includes(where)) {
- socket.emit('action', 'secret', [where, owner]);
- game.actions = null;
- }
-}
-
-function select_battle_hit(evt) { send_action('battle_hit', evt.target.block); }
-function select_battle_fire(evt) { send_action('battle_fire', evt.target.block); }
-function select_battle_retreat(evt) { send_action('battle_retreat', evt.target.block); }
-
-function select_battle_pass(evt) {
- if (window.confirm("Are you sure that you want to PASS with " + block_name(evt.target.block) + "?"))
- send_action('battle_pass', evt.target.block);
-}
-
-
build_map();
document.getElementById("blocks").classList.add(label_style+'-labels');
@@ -796,6 +700,3 @@ document.getElementById("battle").classList.add(label_style+'-labels');
drag_element_with_mouse("#battle", "#battle_header");
scroll_with_middle_mouse("main");
-init_map_zoom();
-init_shift_zoom();
-init_client([ "Caesar", "Pompeius" ]);
diff --git a/rules.js b/rules.js
index dc21cf2..42f972e 100644
--- a/rules.js
+++ b/rules.js
@@ -124,7 +124,7 @@ function clear_undo() {
function push_undo() {
game.undo.push(JSON.stringify(game, (k,v) => {
- if (k === 'undo') return undefined;
+ if (k === 'undo') return 0;
if (k === 'log') return v.length;
return v;
}));
@@ -133,7 +133,7 @@ function push_undo() {
function pop_undo() {
let undo = game.undo;
let save_log = game.log;
- Object.assign(game, JSON.parse(undo.pop()));
+ game = JSON.parse(undo.pop());
game.undo = undo;
save_log.length = game.log;
game.log = save_log;
@@ -258,13 +258,14 @@ function eliminate_block(who) {
log(block_name(who), " is eliminated.");
game.location[who] = DEAD;
game.steps[who] = BLOCKS[who].steps;
+ delete game.owner[who];
}
}
function disband_block(who) {
- game.owner[who] = BLOCKS[who].owner;
game.location[who] = LEVY;
game.steps[who] = BLOCKS[who].steps;
+ delete game.owner[who];
}
function reduce_block(who) {
@@ -2383,7 +2384,7 @@ exports.ready = function (scenario, options, players) {
exports.setup = function (seed, scenario, options) {
game = {
seed: seed,
- tournament: options.tournament ? 1 : 0,
+ tournament: options && options.tournament ? 1 : 0,
c_hand: [],
p_hand: [],
c_card: 0,
@@ -2468,7 +2469,7 @@ exports.action = function (state, current, action, arg) {
S[action](arg, current);
else
throw new Error("Invalid action: " + action);
- return state;
+ return game;
}
exports.resign = function (state, current) {
@@ -2482,7 +2483,7 @@ exports.resign = function (state, current) {
game.result = enemy(current);
game.victory = current + " resigned."
}
- return state;
+ return game;
}
function make_battle_view() {
@@ -2507,7 +2508,7 @@ function make_battle_view() {
function fill_cell(name, p, fn) {
for (let b in BLOCKS) {
if (game.location[b] === game.where & block_owner(b) === p && fn(b)) {
- bv[name].push([b, game.steps[b], game.moved[b]?1:0])
+ bv[name].push(b);
}
}
}
@@ -2533,6 +2534,8 @@ function observer_hand() {
return hand;
}
+exports.is_checkpoint = (a, b) => a.turn !== b.turn;
+
exports.view = function(state, current) {
game = state;
@@ -2542,17 +2545,18 @@ exports.view = function(state, current) {
log: game.log,
year: game.year,
turn: game.turn,
+ active: game.active,
c_vp: game.c_vp,
p_vp: game.p_vp,
c_card: (game.show_cards || current === CAESAR) ? game.c_card : 0,
p_card: (game.show_cards || current === POMPEIUS) ? game.p_card : 0,
hand: (current === CAESAR) ? game.c_hand : (current === POMPEIUS) ? game.p_hand : observer_hand(),
who: (game.active === current) ? game.who : null,
- where: game.where,
- known: {},
- secret: { Caesar: {}, Pompeius: {}, Cleopatra: {} },
+ location: game.location,
+ owner: game.owner,
+ steps: game.steps,
+ moved: game.moved,
battle: null,
- active: game.active,
prompt: null,
actions: null,
};
@@ -2571,26 +2575,5 @@ exports.view = function(state, current) {
view.surprise = game.surprise;
}
- for (let b in BLOCKS) {
- let jupiter = (BLOCKS[b].owner !== block_owner(b)) ? 1 : 0;
- if (game.state === 'game_over') {
- if (game.location[b] !== LEVY)
- view.known[b] = [ game.location[b], game.steps[b], 0, jupiter ];
- } else if (block_owner(b) === current || game.location[b] === DEAD) {
- view.known[b] = [ game.location[b], game.steps[b], game.moved[b]?1:0, jupiter ];
- } else {
- let a = game.location[b];
- let o = BLOCKS[b].owner;
- if (b === CLEOPATRA)
- o = CLEOPATRA;
- if (a !== LEVY) {
- let list = view.secret[o];
- if (!(a in list))
- list[a] = [];
- list[a].push([game.moved[b]?1:0, jupiter]);
- }
- }
- }
-
return view;
}