summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-02-14 16:17:56 +0100
committerTor Andersson <tor@ccxvii.net>2023-02-18 11:54:52 +0100
commit0babd26f9e688f33829fe7de997bbacc88eda91a (patch)
treeb49cd32f50266c4d6d31d95be835ddcf229f8bb6 /rules.js
parent2d93e87ab27d84d8840a0a3b06c519beac9c62a1 (diff)
downloadwilderness-war-0babd26f9e688f33829fe7de997bbacc88eda91a.tar.gz
Retreat lone leaders from spaces where enemy units enter.
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js102
1 files changed, 95 insertions, 7 deletions
diff --git a/rules.js b/rules.js
index 4efeb84..5e8b4be 100644
--- a/rules.js
+++ b/rules.js
@@ -16,12 +16,17 @@
// features
// TODO: track 'held'
// TODO: battle VP awards
-// TODO: leaders alone - stop search in space
-// TODO: leaders alone - retreat
// TODO: end of late season
+// TODO: french_regulars event played - montcalm not entered or dead separate state (merge DEAD/UNUSED consts)
// TODO: trace supply
// TODO: infiltration
+// check rules/implementation:
+// TODO: leaders alone - retreat (reinforcement events that place units)
+
+// GRAPHICS: badge for pool/dead leaders
+// GRAPHICS: tooltip for leader stack and strength
+
const { spaces, pieces, cards } = require("./data");
const BRITAIN = 'Britain';
@@ -1212,6 +1217,13 @@ function count_enemy_units_in_space(space) {
return n;
}
+function has_unbesieged_enemy_leader(space) {
+ for (let p = first_enemy_leader; p <= last_enemy_leader; ++p)
+ if (is_piece_in_space(p, space) && !is_piece_inside(p))
+ return true;
+ return false;
+}
+
function has_unbesieged_enemy_units(space) {
for (let p = first_enemy_unit; p <= last_enemy_unit; ++p)
if (is_piece_in_space(p, space) && !is_piece_inside(p))
@@ -1979,6 +1991,10 @@ function search_boat_move(who, start_space, start_cost, max_cost) {
n_cost = 18; // may not continue
}
+ // Stop when entering a space with a lone enemy leader(s) to force a retreat
+ if (!is_lone_ld && has_unbesieged_enemy_leader(next))
+ must_stop = true; // May continue after retreat
+
// No movement points left.
if (n_cost >= max_cost)
must_stop = true;
@@ -2061,6 +2077,10 @@ function search_land_move(who, start_space, start_cost, max_cost) {
n_cost = 9; // may not continue
}
+ // Stop when entering a space with a lone enemy leader(s) to force a retreat
+ if (!is_lone_ld && has_unbesieged_enemy_leader(next))
+ must_stop = true; // May continue after retreat
+
// No movement points left.
if (n_cost >= max_cost)
must_stop = true;
@@ -3056,18 +3076,18 @@ function end_move_step(final) {
}
if (has_enemy_stockade(where)) {
if (force_has_drilled_troops(who)) {
- capture_enemy_stockade(where)
+ capture_enemy_stockade(where);
if (can_play_massacre())
return goto_massacre('massacre_after_move');
}
}
- resume_move();
} else if (final) {
game.move.start_cost = 99;
- resume_move();
- } else {
- resume_move();
}
+ if (!is_lone_leader(who) && has_unbesieged_enemy_leader(where))
+ goto_retreat_lone_leader();
+ else
+ resume_move();
}
states.massacre_after_move = {
@@ -4476,6 +4496,7 @@ function can_defender_retreat_from(p, from) {
return can_retreat;
}
+// TODO: auto-select pieces to retreat?
states.retreat_defender = {
prompt() {
let from = battle_space();
@@ -4550,6 +4571,73 @@ function end_retreat() {
end_move_step(true);
}
+function goto_retreat_lone_leader() {
+ clear_undo();
+ set_active(enemy());
+ game.state = 'retreat_lone_leader';
+}
+
+function pick_unbesieged_leader(s) {
+ for (let p = first_friendly_leader; p <= last_friendly_leader; ++p)
+ if (is_piece_in_space(p, s) && !is_piece_inside(p))
+ return p;
+ return 0;
+}
+
+states.retreat_lone_leader = {
+ prompt() {
+ let from = moving_piece_space();
+ let who = pick_unbesieged_leader(from);
+ view.prompt = `Retreat lone leader ${piece_name(who)} from ${space_name(from)}.`;
+ view.who = who;
+ let can_retreat = false;
+ if (game.active === BRITAIN && has_amphib(from)) {
+ for_each_british_controlled_port(to => {
+ can_retreat = true;
+ gen_action_space(to)
+ });
+ }
+ if (can_defender_retreat_inside(who, from)) {
+ can_retreat = true;
+ gen_action_space(from);
+ }
+ for_each_exit(from, to => {
+ if (can_defender_retreat_from_to(who, from, to)) {
+ can_retreat = true;
+ gen_action_space(to);
+ }
+ });
+ if (!can_retreat)
+ gen_action('eliminate');
+ },
+ eliminate() {
+ let from = moving_piece_space();
+ let who = pick_unbesieged_leader(from);
+ eliminate_piece(who);
+ resume_retreat_lone_leader(from);
+ },
+ space(to) {
+ let from = moving_piece_space();
+ let who = pick_unbesieged_leader(from);
+ if (from === to) {
+ log("retreats inside fortification");
+ set_force_inside(who);
+ } else {
+ log("retreats to " + space_name(to));
+ move_piece_to(who, to);
+ }
+ resume_retreat_lone_leader(from);
+ },
+}
+
+function resume_retreat_lone_leader(from) {
+ let who = pick_unbesieged_leader(from);
+ if (!who) {
+ set_active(enemy());
+ resume_move();
+ }
+}
+
// SIEGE
const SIEGE_TABLE = [ 0, 0, 0, 1, 1, 1, 2, 2 ];