summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--data.js10
-rw-r--r--play.html8
-rw-r--r--rules.js114
-rw-r--r--ui.js16
4 files changed, 115 insertions, 33 deletions
diff --git a/data.js b/data.js
index c6a7ad8..d1711a8 100644
--- a/data.js
+++ b/data.js
@@ -104,9 +104,9 @@ const TOWNS = {
"England2":{"x":140,"y":961},
"England3":{"x":138,"y":1047},
*/
- "Germania":{"x":139,"y":273},
+ "Germania":{"x":140,"y":272},
"France":{"x":140,"y":573},
- "England":{"x":139,"y":873},
+ "England":{"x":140,"y":873},
"FP":{"x":50,"y":2150},
"SP":{"x":50,"y":2150},
"Dead":{"x":50,"y":80},
@@ -258,9 +258,9 @@ const PORTS = [];
town('Y', 0.0, 0.0, 30, "Pool", "SP", 0, "pool");
town('Y', 1.0, 1.0, 30, "Pool", "Dead", 0, "pool");
- town('X', 0.5, 0.5, 3, "Staging", "England", 0, "staging");
- town('X', 0.5, 0.5, 3, "Staging", "France", 0, "staging");
- town('X', 0.5, 0.5, 3, "Staging", "Germania", 0, "staging");
+ town('Y', 1.0, 0.5, 3, "Staging", "England", 0, "staging");
+ town('Y', 1.0, 0.5, 3, "Staging", "France", 0, "staging");
+ town('Y', 1.0, 0.5, 3, "Staging", "Germania", 0, "staging");
town('X', 1.0, 0.5, 3, "Syria", "Aleppo", 3, "town");
diff --git a/play.html b/play.html
index 7ec0e98..4b9a223 100644
--- a/play.html
+++ b/play.html
@@ -245,10 +245,10 @@ body.shift .block.known:hover {
#FR, #ER { min-height: 40px; }
#FC.c0, #EC.c0 { display: none; }
-#FC.c1, #EC.c1 { width: 90px; display: block; }
-#FC.c2, #EC.c2 { width: 180px; display: block; }
-#FC.c3, #EC.c3 { width: 270px; display: block; }
-#FC.c4, #EC.c4 { width: 360px; display: block; }
+#FC.c1, #EC.c1 { width: 90px; }
+#FC.c2, #EC.c2 { width: 180px; }
+#FC.c3, #EC.c3 { width: 270px; }
+#FC.c4, #EC.c4 { width: 360px; }
/* CARD AND BLOCK IMAGES */
diff --git a/rules.js b/rules.js
index 66ca07e..c341e5c 100644
--- a/rules.js
+++ b/rules.js
@@ -6,17 +6,15 @@
// TODO: optional rule - iron bridge
// TODO: optional rule - force marches
-// TODO: hide blocks in battle deployment and sallying etc
// TODO: battle dialog messages
-// TODO: nicer looking battle dialog -- reserve, castle*, field, field, castle*, reserve
-// TODO: battle dialog block order
-// TODO: draw phase
// TODO: winter turn
// TODO: winter campaign
// TODO: crusader arrival movement
+// TODO: alternate home seats
+
exports.scenarios = [
"Third Crusade"
];
@@ -632,13 +630,10 @@ function can_muster_to(muster) {
}
function can_muster_anywhere() {
- if (game.moves > 0)
- return true;
- for (let where of game.mustered) {
+ for (let where in TOWNS)
if (is_friendly_field(where))
if (can_muster_to(where))
return true;
- }
return false;
}
@@ -982,6 +977,7 @@ function start_player_turn() {
log("");
log("Start " + game.active + " turn.");
reset_road_limits();
+ game.main_road = {};
let card = CARDS[game.active == FRANKS ? game.f_card : game.s_card];
if (card.event)
goto_event_card(card.event);
@@ -1155,8 +1151,6 @@ function move_block(who, from, to) {
function goto_move_phase(moves) {
game.state = 'move_phase';
game.moves = moves;
- game.mustered = [];
- game.main_road = {};
}
function end_move_phase() {
@@ -1668,6 +1662,8 @@ function start_combat() {
}
function end_combat() {
+ log("~ Combat Ends ~");
+
console.log("END COMBAT IN", game.where);
lift_siege(game.where);
@@ -1680,7 +1676,7 @@ function end_combat() {
delete game.sallying;
game.where = null;
game.flash = "";
- game.battle_round = 0;
+ game.combat_round = 0;
resume_combat_phase();
}
@@ -1838,6 +1834,7 @@ function goto_combat_round(combat_round) {
if (game.storming.length > 0) {
log("Storming canceled by arriving relief force.");
console.log("STORMING CANCELED");
+ game.halfhit = null;
game.storming.length = 0;
}
let old_attacker = game.attacker[game.where];
@@ -1952,7 +1949,6 @@ states.declare_sally = {
} else if (count_reserves(game.where) > 0) {
next_combat_round();
} else {
- log("~ Combat Ends ~");
goto_siege_attrition();
}
},
@@ -1975,17 +1971,17 @@ function sally_with_block(who) {
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);
game.sallying.length = 0;
// withdraw all storming blocks to the field.
+ game.halfhit = null;
game.storming.length = 0;
if (is_contested_field(game.where)) {
+ log("~ Retreat ~");
game.active = game.attacker[game.where];
game.state = 'retreat';
game.summary = [];
@@ -2067,15 +2063,16 @@ states.retreat_to = {
function goto_siege_attrition() {
console.log("SIEGE ATTRITION");
+ log("~ Siege Attrition ~");
game.active = besieging_player(game.where);
for (let b in BLOCKS) {
if (is_block_in_castle_in(b, game.where)) {
let die = roll_d6();
if (die <= 3) {
- log("Siege attrition: " + DIE_HIT[die] + ".");
+ log("Attrition roll " + DIE_HIT[die] + ".");
reduce_block(b);
} else {
- log("Siege attrition: " + DIE_MISS[die] + ".");
+ log("Attrition roll " + DIE_MISS[die] + ".");
}
}
}
@@ -2226,7 +2223,7 @@ function resume_storm_battle() {
console.log("STORM BATTLE WON BY DEFENDER", ENEMY[game.active]);
game.halfhit = null;
log("Storming repulsed.");
- return next_combat_round();
+ return goto_regroup();
}
if (game.storming.length == 0) {
@@ -2578,9 +2575,78 @@ states.retreat_in_battle = {
function goto_draw_phase() {
delete game.combat_list;
+
+ //if (game.year > 1187 && !is_winter()) {
+ if (!is_winter()) {
+ game.active = game.p1;
+ return start_draw_phase();
+ }
end_game_turn();
}
+function start_draw_phase() {
+ if (game.active == FRANKS) {
+ game.who = select_random_block(F_POOL);
+ game.state = 'draw_phase';
+ } else {
+ game.who = select_random_block(S_POOL);
+ game.state = 'draw_phase';
+ }
+}
+
+states.draw_phase = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "Waiting for " + game.active + " to place drawn block.";
+ view.prompt = "Draw Phase: Place " + game.who + ".";
+ gen_action(view, 'next');
+ switch (block_type(game.who)) {
+ case 'crusaders':
+ gen_action(view, 'town', block_home(game.who));
+ break;
+ case 'pilgrims':
+ for (let town in TOWNS)
+ if (is_friendly_port(town) || can_enter_besieged_port(town))
+ gen_action(view, 'town', town);
+ break;
+ case 'outremers':
+ case 'emirs':
+ case 'nomads':
+ for (let town in TOWNS)
+ if (is_friendly_town(town))
+ gen_action(view, 'town', town);
+ break;
+ }
+ },
+ town: function (where) {
+ let type = block_type(game.who);
+ let home = block_home(game.who);
+
+ log(game.active + " arrive in " + where + ".");
+
+ game.location[game.who] = where;
+ if ((type == 'outremers' || type == 'emirs' || type == 'nomads') && (where != home))
+ game.steps[game.who] = 1;
+ else
+ game.steps[game.who] = block_max_steps(game.who);
+
+ game.who = null;
+ end_draw_phase();
+ },
+ next: function () {
+ end_draw_phase();
+ },
+}
+
+function end_draw_phase() {
+ if (game.active == game.p1) {
+ game.active = game.p2;
+ start_draw_phase();
+ } else {
+ end_game_turn();
+ }
+}
+
// GAME OVER
function goto_game_over() {
@@ -2657,10 +2723,16 @@ function make_battle_view() {
show_castle: game.storming.length > 0 && game.state != 'declare_storm',
};
- battle.title = game.attacker[game.where] + " attack " + game.where;
- if (game.combat_round == 0) {
- battle.title += " \u2014 combat deployment";
- }
+ if (is_under_siege(game.where))
+ battle.title = ENEMY[game.castle_owner] + " besiege " + game.where;
+ else
+ battle.title = game.attacker[game.where] + " attack " + game.where;
+ if (game.combat_round == 0)
+ battle.title += " \u2014 Combat Deployment";
+ else
+ battle.title += " \u2014 Round " + game.combat_round;
+ if (game.where == game.jihad)
+ battle.title += " \u2014 Jihad!";
function fill_cell(cell, owner, fn) {
for (let b in BLOCKS)
diff --git a/ui.js b/ui.js
index 71b0846..1b08723 100644
--- a/ui.js
+++ b/ui.js
@@ -7,6 +7,9 @@ const ENEMY = { Saracens: "Franks", Franks: "Saracens" }
const DEAD = "Dead";
const F_POOL = "FP";
const S_POOL = "SP";
+const ENGLAND = "England";
+const FRANCE = "France";
+const GERMANIA = "Germania";
let label_layout = window.localStorage['crusader-rex/label-layout'] || 'spread';
@@ -373,7 +376,9 @@ function layout_blocks(location, secret, known) {
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))
+ if (label_layout == 'spread' ||
+ (location == S_POOL || location == F_POOL || location == DEAD ||
+ location == ENGLAND || location == FRANCE || location == GERMANIA))
layout_blocks_spread(location, secret, known);
else
layout_blocks_stacked(location, secret, known);
@@ -454,6 +459,8 @@ function position_block(town, row, n_rows, col, n_cols, element) {
let space = TOWNS[town];
let block_size = 60+6;
let padding = 4;
+ if (town == ENGLAND || town == FRANCE || town == GERMANIA)
+ padding = 21;
let offset = block_size + padding;
let row_size = (n_rows-1) * offset;
let col_size = (n_cols-1) * offset;
@@ -552,9 +559,12 @@ function update_map() {
if (town == DEAD)
moved = " moved";
if (info.owner == player || info.owner == ASSASSINS) {
- let image = " known block_" + info.image;
+ let image = " block_" + info.image;
let steps = " r" + (info.steps - game.steps[b]);
- element.classList = info.owner + " block" + image + steps + moved;
+ let known = " known"
+ if ((town == S_POOL || town == F_POOL) && b != game.who)
+ known = "";
+ element.classList = info.owner + known + " block" + image + steps + moved;
layout[town].south.push(element);
} else {
let besieging = (game.sieges[town] == info.owner) ? " besieging" : "";