summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.html11
-rw-r--r--rules.js95
-rw-r--r--ui.js8
3 files changed, 91 insertions, 23 deletions
diff --git a/play.html b/play.html
index 3ff067d..a62bd78 100644
--- a/play.html
+++ b/play.html
@@ -200,10 +200,14 @@ body.shift .block.known:hover {
.battle_line > td > div { min-width: 800px; }
.battle td { border: none; }
-#FA, #FC, #FD, #FR, #EA, #EC, #ER { margin: 0px; }
-#FC, #EC { background-color: gray; }
+#FA, #FB, #FC, #FD, #FR, #EA, #EB, #EC, #ER { margin: 0px; padding: 5px; }
.battle .battle_menu { margin: 10px 5px; }
+#FR, #ER { background-color: mediumseagreen; }
+#FA, #EA { background-color: darkseagreen; }
+#FB, #EB { background-color: darkgray; }
+#FC, #EC { background-color: gray; }
+
/* CARD AND BLOCK IMAGES */
.card_back{background-image:url('cards/card_back.jpg')}
@@ -298,8 +302,10 @@ body.shift .block.known:hover {
<th class="battle_header" colspan=4></th>
<tr class="battle_reserves enemy"><td><div id="ER"></div></td>
<tr class="battle_line enemy"><td><div id="EC"></div></td>
+<tr class="battle_line enemy"><td><div id="EB"></div></td>
<tr class="battle_line enemy"><td><div id="EA"></div></td>
<tr class="battle_line friendly"><td><div id="FA"></div></td>
+<tr class="battle_line friendly"><td><div id="FB"></div></td>
<tr class="battle_line friendly"><td><div id="FC"></div></td>
<tr class="battle_reserves friendly"><td><div id="FR"></div></td>
<tr>
@@ -350,6 +356,7 @@ body.shift .block.known:hover {
<button id="end_retreat_button" class="hide" onclick="on_button_end_retreat()">End retreat</button>
<button id="end_regroup_button" class="hide" onclick="on_button_end_regroup()">End regroup</button>
<button id="end_move_phase_button" class="hide" onclick="on_button_end_move_phase()">End move phase</button>
+ <button id="jihad_button" class="hide" onclick="on_button_jihad()">Jihad</button>
<button id="pass_button" class="hide" onclick="on_button_pass()">Pass</button>
<button id="next_button" class="hide" onclick="on_button_next()">Next</button>
<button id="undo_button" class="hide" onclick="on_button_undo()">Undo</button>
diff --git a/rules.js b/rules.js
index 3af5dbd..2801444 100644
--- a/rules.js
+++ b/rules.js
@@ -6,8 +6,18 @@
// TODO: optional rule - iron bridge
// TODO: optional rule - force marches
-// TODO: strict move order for group moves?
-// Move Phase -> Group Move / Muster / Sea Move -> Move Phase
+// TODO: hide blocks in battle deployment and sallying etc
+// TODO: battle dialog messages
+// TODO: nicer looking battle dialog
+// TODO: battle dialog block order
+
+// TODO: event cards
+
+// TODO: draw phase
+// TODO: winter turn
+// TODO: winter campaign
+
+// TODO: crusader arrival movement
exports.scenarios = [
"Third Crusade"
@@ -256,6 +266,12 @@ function can_activate(who) {
!game.moved[who];
}
+function can_activate_for_sea_move(who) {
+ return block_owner(who) == game.active &&
+ is_block_on_map(who) &&
+ !game.moved[who];
+}
+
function road_id(a, b) {
return (a < b) ? a + "/" + b : b + "/" + a;
}
@@ -358,7 +374,6 @@ function is_port(where) {
}
function is_friendly_port(where) {
- // TODO: Tripoli/Tyre are friendly to besieged defender!
return TOWNS[where].port && is_friendly_town(where);
}
@@ -429,21 +444,47 @@ function can_use_richards_sea_legs(who, to) {
return false;
}
-function can_block_sea_move_to(who, from, to) {
+function can_enter_besieged_port(where) {
+ // Tripoli and Tyre are friendly to besieged defender!
+ if (where == "Tripoli" || where == "Tyre")
+ if (besieged_player(where) == game.active)
+ return count_blocks_in_castle(where) < castle_limit(where);
+ return false;
+}
+
+function can_leave_besieged_port(where) {
+ // Tripoli and Tyre are friendly to besieged defender!
+ if (where == "Tripoli" || where == "Tyre")
+ if (besieged_player(where) == game.active)
+ return true;
+ return false;
+}
+
+function can_block_sea_move_to(who, to) {
if (is_port(to)) {
if (can_use_richards_sea_legs(who, to))
return true;
+ if (can_enter_besieged_port(to))
+ return true;
return is_friendly_port(to);
}
return false;
}
+function can_block_sea_move_from(who, from) {
+ if (is_friendly_port(from))
+ return true;
+ if (can_leave_besieged_port(from))
+ return true;
+ return false;
+}
+
function can_block_sea_move(who) {
- if (can_activate(who)) {
+ if (can_activate_for_sea_move(who)) {
let from = game.location[who];
- if (is_friendly_port(from)) {
+ if (can_block_sea_move_from(who, from)) {
for (let to of PORTS)
- if (to != from && can_block_sea_move_to(who, from, to))
+ if (to != from && can_block_sea_move_to(who, to))
return true;
}
}
@@ -1033,7 +1074,6 @@ states.sea_move = {
return view.prompt = "Move Phase: Waiting for " + game.active + ".";
view.prompt = format_moves("Sea Move: ", "Choose a block to sea move");
gen_action_undo(view);
- // gen_action(view, 'end_sea_move');
for (let b in BLOCKS)
if (can_block_sea_move(b))
gen_action(view, 'block', b);
@@ -1060,7 +1100,7 @@ states.sea_move_to = {
gen_action(view, 'block', game.who);
let from = game.location[game.who];
for (let to of PORTS)
- if (to != from && can_block_sea_move_to(game.who, from, to))
+ if (to != from && can_block_sea_move_to(game.who, to))
gen_action(view, 'town', to);
},
town: function (to) {
@@ -1072,13 +1112,22 @@ states.sea_move_to = {
lift_siege(from);
- // English Crusaders attack!
- if (!is_friendly_port(to)) {
+ remove_from_array(game.castle, game.who);
+
+ if (besieged_player(to) == game.active) {
+ // Move into besieged fortified port
+ game.castle.push(game.who);
+ log(game.active + " sea moves:\n" + from + " \u2192 " + to + " castle.");
+
+ } else if (!is_friendly_port(to)) {
+ // English Crusaders attack!
game.attacker[to] = FRANK;
game.main_road[to] = "England";
- logp(game.active + " sea moves to " + to + ATTACK_MARK + ".");
+ log(game.active + " sea moves:\n" + from + " \u2192 " + to + ATTACK_MARK + ".");
+
} else {
- logp(game.active + " sea moves to " + to + ".");
+ // Normal move.
+ log(game.active + " sea moves:\n" + from + " \u2192 " + to + ".");
}
game.who = null;
@@ -1395,7 +1444,7 @@ function start_combat(where) {
} else {
game.attacker[game.where] = besieging_player(game.where);
console.log("CONTINUE SIEGE");
- log("Siege continues from previous turn.");
+ log("Existing siege continues.");
next_combat_round();
}
} else {
@@ -1691,6 +1740,7 @@ states.declare_sally = {
} else if (count_reserves(game.where) > 0) {
next_combat_round();
} else {
+ log("~ Combat Ends ~");
goto_siege_attrition();
}
},
@@ -1702,6 +1752,8 @@ states.declare_sally = {
function goto_retreat_after_combat() {
console.log("RETREAT AFTER COMBAT");
+ log("~ Combat Ends ~");
+
// withdraw all sallying blocks to castle.
for (let b of game.sallying)
game.castle.push(b);
@@ -2346,8 +2398,8 @@ function compare_block_initiative(a, b) {
function make_battle_view() {
let battle = {
- FA: [], FC: [], FR: [],
- SA: [], SC: [], SR: [],
+ FA: [], FB: [], FC: [], FR: [],
+ SA: [], SB: [], SC: [], SR: [],
storming: game.storming,
sallying: game.sallying,
halfhit: game.halfhit,
@@ -2364,16 +2416,17 @@ function make_battle_view() {
if (game.location[b] == game.where & block_owner(b) == owner && fn(b))
cell.push([b, game.steps[b], game.moved[b]?1:0])
cell.sort((a,b) => compare_block_initiative(a[0], b[0]));
- console.log("CELL", cell);
}
- fill_cell(battle.FR, FRANK, b => is_battle_reserve(b));
- fill_cell(battle.FA, FRANK, b => !is_battle_reserve(b) && !is_block_in_castle(b));
+ fill_cell(battle.FA, FRANK, b => !is_battle_reserve(b) && !is_block_in_castle(b) && game.storming.includes(b));
+ fill_cell(battle.FB, FRANK, b => !is_battle_reserve(b) && !is_block_in_castle(b) && !game.storming.includes(b));
fill_cell(battle.FC, FRANK, b => !is_battle_reserve(b) && is_block_in_castle(b));
+ fill_cell(battle.FR, FRANK, b => is_battle_reserve(b));
- fill_cell(battle.SR, SARACEN, b => is_battle_reserve(b));
- fill_cell(battle.SA, SARACEN, b => !is_battle_reserve(b) && !is_block_in_castle(b));
+ fill_cell(battle.SA, SARACEN, b => !is_battle_reserve(b) && !is_block_in_castle(b) && game.storming.includes(b));
+ fill_cell(battle.SB, SARACEN, b => !is_battle_reserve(b) && !is_block_in_castle(b) && !game.storming.includes(b));
fill_cell(battle.SC, SARACEN, b => !is_battle_reserve(b) && is_block_in_castle(b));
+ fill_cell(battle.SR, SARACEN, b => is_battle_reserve(b));
return battle;
}
diff --git a/ui.js b/ui.js
index 80a056a..9ef68a0 100644
--- a/ui.js
+++ b/ui.js
@@ -362,6 +362,10 @@ function update_steps(b, steps, element) {
}
function layout_blocks(location, secret, known) {
+ if (label_layout == 'stack')
+ document.getElementById("map").classList.add("stack_layout");
+ else
+ document.getElementById("map").classList.remove("stack_layout");
if (label_layout == 'spread' || (location == S_POOL || location == F_POOL || location == DEAD))
layout_blocks_spread(location, secret, known);
else
@@ -677,15 +681,19 @@ function update_battle() {
if (player == FRANK) {
fill_cell("FR", game.battle.FR, true);
fill_cell("FA", game.battle.FA, false);
+ fill_cell("FB", game.battle.FB, false);
fill_cell("FC", game.battle.FC, false);
fill_cell("EA", game.battle.SA, false);
+ fill_cell("EB", game.battle.SB, false);
fill_cell("EC", game.battle.SC, false);
fill_cell("ER", game.battle.SR, true);
} else {
fill_cell("ER", game.battle.FR, true);
fill_cell("EA", game.battle.FA, false);
+ fill_cell("EB", game.battle.FB, false);
fill_cell("EC", game.battle.FC, false);
fill_cell("FA", game.battle.SA, false);
+ fill_cell("FB", game.battle.SB, false);
fill_cell("FC", game.battle.SC, false);
fill_cell("FR", game.battle.SR, true);
}