summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2024-05-19 00:21:31 +0200
committerTor Andersson <tor@ccxvii.net>2024-08-21 00:28:20 +0200
commita8cfb2c1011ac4b46bc0bb500798e5d718ec2d73 (patch)
treefbe527e29f3bcaf9e73b7771565b4dc04417f762
parentce0a313d66852b7d8c228cf992d260b665c51ad8 (diff)
downloadwashingtons-war-a8cfb2c1011ac4b46bc0bb500798e5d718ec2d73.tar.gz
wip put move state in sub-object
-rw-r--r--play.js12
-rw-r--r--rules.js624
2 files changed, 325 insertions, 311 deletions
diff --git a/play.js b/play.js
index 5d649a1..eb86314 100644
--- a/play.js
+++ b/play.js
@@ -242,19 +242,19 @@ function build_map() {
}
function get_space_pc(space) {
- return view.spc[space] & 3
+ return view.cupc[space] & 3
}
function count_british_cu(s) {
- return (view.spc[s] & CU_BRITISH_MASK) >>> CU_BRITISH_SHIFT
+ return (view.cupc[s] & CU_BRITISH_MASK) >>> CU_BRITISH_SHIFT
}
function count_american_cu(s) {
- return (view.spc[s] & CU_AMERICAN_MASK) >>> CU_AMERICAN_SHIFT
+ return (view.cupc[s] & CU_AMERICAN_MASK) >>> CU_AMERICAN_SHIFT
}
function count_french_cu(s) {
- return (view.spc[s] & CU_FRENCH_MASK) >>> CU_FRENCH_SHIFT
+ return (view.cupc[s] & CU_FRENCH_MASK) >>> CU_FRENCH_SHIFT
}
function update_units() {
@@ -329,7 +329,7 @@ function update_units() {
let offset = []
for (let g in GENERALS) {
let e = ui.generals[g]
- let loc = view.loc[g]
+ let loc = view.loca[g]
let space = SPACES[loc] || BOXES[loc]
if (space) {
let o = offset[loc] | 0
@@ -359,7 +359,7 @@ function update_units() {
}
}
clear_group("cu")
- for (let s = 0; s < view.spc.length; ++s) {
+ for (let s = 0; s < view.cupc.length; ++s) {
add_cu_marker(s, count_british_cu(s), [ "cu", "british" ])
add_cu_marker(s, count_american_cu(s), [ "cu", "american" ])
add_cu_marker(s, count_french_cu(s), [ "cu", "french" ])
diff --git a/rules.js b/rules.js
index c23b1f4..6e0c3e1 100644
--- a/rules.js
+++ b/rules.js
@@ -1,13 +1,14 @@
"use strict"
+// TODO: capture washington is messy
// TODO: campaign messed up who is who after battle
// TODO: retreat with 0 CU after battle
-// TODO: bit flags for regulars, european_war, french alliance triggered
+// TODO: bit flags for regulars, european_war, french alliance triggered, etc
/* DATA */
-const data = require("./data")
+const data = require("./data.js")
const CARDS = data.cards
const SPACES = data.spaces
@@ -88,8 +89,8 @@ const SOUTH_OF_WINTER_ATTRITION_LINE = [ 11, 12, 13 ]
const CAMPAIGN_CARDS = [ 67, 68, 69, 70 ]
const DECLARATION_OF_INDEPENDENCE = 99
const BARON_VON_STEUBEN = 86
-const WAR_ENDS_1779 = 71
-const BENJAMIN_FRANKLIN = 101
+// const WAR_ENDS_1779 = 71
+// const BENJAMIN_FRANKLIN = 101
const general_count = data.generals.length
const space_count = 66
@@ -97,11 +98,11 @@ const all_spaces = new Array(space_count).fill(0).map((_,i)=>i)
const ENEMY = { [P_AMERICA]: P_BRITAIN, [P_BRITAIN]: P_AMERICA }
-let states = {}
-let events = {}
+var states = {}
+var events = {}
-let game
-let view
+var game
+var view
/* SETUP */
@@ -115,9 +116,13 @@ function setup_game(seed) {
// tracks
year: 1775,
+
french_alliance_triggered: false,
european_war: false,
regulars: true,
+ congress_was_dispersed: false,
+ pennsylvania_and_new_jersey_line_mutinies: false,
+ reshuffle: false,
// played cards
war_ends: 0,
@@ -127,8 +132,8 @@ function setup_game(seed) {
french_alliance: 0,
congress: PHILADELPHIA,
french_navy: -1,
- loc: new Array(general_count).fill(NOWHERE),
- spc: new Array(space_count + 2).fill(PC_NONE),
+ loca: new Array(general_count).fill(NOWHERE),
+ cupc: new Array(space_count + 2).fill(PC_NONE),
// hands & card deck
a_hand: [],
@@ -136,13 +141,15 @@ function setup_game(seed) {
a_queue: 0,
b_queue: 0,
- reshuffle: false,
+ last_played: 0,
+ did_discard_event: 0,
deck: null,
removed: [],
- // transient state
- moved: [],
- mcu: [],
+ mv: [],
+ mvcu: [],
+
+ count: 0,
}
set_space_pc(QUEBEC, PC_BRITISH)
@@ -273,7 +280,7 @@ function discard_card(c, reason) {
}
function can_exchange_for_discard(c) {
- if (game.did_discard_event > 0) {
+ if (game.did_discard_event) {
if (game.active === P_BRITAIN)
return true
return CARDS[c].count > 1
@@ -362,7 +369,7 @@ function is_american_militia(space) {
}
function is_american_winter_offensive() {
- if (game.who === WASHINGTON && game.a_hand.length === 0)
+ if (game.move.who === WASHINGTON && game.a_hand.length === 0)
return true
return false
}
@@ -370,12 +377,12 @@ function is_american_winter_offensive() {
/* PC */
function set_space_pc(space, pc) {
- game.spc[space] &= ~3
- game.spc[space] |= pc
+ game.cupc[space] &= ~3
+ game.cupc[space] |= pc
}
function get_space_pc(space) {
- return game.spc[space] & 3
+ return game.cupc[space] & 3
}
function has_no_pc(space) {
@@ -468,34 +475,34 @@ function get_colony_control(c) {
/* CU */
function reset_moved_cu() {
- map_clear(game.mcu)
+ map_clear(game.mvcu)
}
function count_british_cu(s) {
- return (game.spc[s] & CU_BRITISH_MASK) >>> CU_BRITISH_SHIFT
+ return (game.cupc[s] & CU_BRITISH_MASK) >>> CU_BRITISH_SHIFT
}
function count_american_cu(s) {
- return (game.spc[s] & CU_AMERICAN_MASK) >>> CU_AMERICAN_SHIFT
+ return (game.cupc[s] & CU_AMERICAN_MASK) >>> CU_AMERICAN_SHIFT
}
function count_french_cu(s) {
- return (game.spc[s] & CU_FRENCH_MASK) >>> CU_FRENCH_SHIFT
+ return (game.cupc[s] & CU_FRENCH_MASK) >>> CU_FRENCH_SHIFT
}
function set_british_cu(s, n) {
- game.spc[s] &= ~CU_BRITISH_MASK
- game.spc[s] |= n << CU_BRITISH_SHIFT
+ game.cupc[s] &= ~CU_BRITISH_MASK
+ game.cupc[s] |= n << CU_BRITISH_SHIFT
}
function set_american_cu(s, n) {
- game.spc[s] &= ~CU_AMERICAN_MASK
- game.spc[s] |= n << CU_AMERICAN_SHIFT
+ game.cupc[s] &= ~CU_AMERICAN_MASK
+ game.cupc[s] |= n << CU_AMERICAN_SHIFT
}
function set_french_cu(s, n) {
- game.spc[s] &= ~CU_FRENCH_MASK
- game.spc[s] |= n << CU_FRENCH_SHIFT
+ game.cupc[s] &= ~CU_FRENCH_MASK
+ game.cupc[s] |= n << CU_FRENCH_SHIFT
}
function has_british_cu(space) {
@@ -526,21 +533,21 @@ function has_enemy_cu(where) {
}
function count_unmoved_british_cu(where) {
- return count_british_cu(where) - map_get(game.mcu, where * 3 + 0, 0)
+ return count_british_cu(where) - map_get(game.mvcu, where * 3 + 0, 0)
}
function count_unmoved_american_cu(where) {
- return count_american_cu(where) - map_get(game.mcu, where * 3 + 1, 0)
+ return count_american_cu(where) - map_get(game.mvcu, where * 3 + 1, 0)
}
function count_unmoved_french_cu(where) {
- return count_french_cu(where) - map_get(game.mcu, where * 3 + 2, 0)
+ return count_french_cu(where) - map_get(game.mvcu, where * 3 + 2, 0)
}
function mark_moved_cu_imp(offset, where, moved) {
if (moved > 0) {
- let old = map_get(game.mcu, where * 3 + offset, 0)
- map_set(game.mcu, where * 3 + offset, old + moved)
+ let old = map_get(game.mvcu, where * 3 + offset, 0)
+ map_set(game.mvcu, where * 3 + offset, old + moved)
}
}
@@ -609,11 +616,11 @@ function move_french_cu(from, to, count) {
/* GENERALS */
function location_of_general(g) {
- return game.loc[g]
+ return game.loca[g]
}
function set_general_location(g, s) {
- game.loc[g] = s
+ game.loca[g] = s
}
function is_general_at_location(g, s) {
@@ -625,15 +632,15 @@ function is_general_on_map(g) {
}
function has_general_moved(g) {
- return set_has(game.moved, g)
+ return set_has(game.mv, g)
}
function set_general_moved(g) {
- set_add(game.moved, g)
+ set_add(game.mv, g)
}
function reset_moved_generals() {
- set_clear(game.moved)
+ set_clear(game.mv)
}
function find_british_general(where) {
@@ -853,46 +860,46 @@ function place_french_reinforcements(who, where) {
move_french_cu(AMERICAN_REINFORCEMENTS, where, count_french_cu(AMERICAN_REINFORCEMENTS))
}
-function pickup_max_british_cu(where) {
- game.carry_british = count_unmoved_british_cu(where)
- if (game.carry_british > 5)
- game.carry_british = 5
- game.carry_american = 0
- game.carry_french = 0
+function pickup_max_british_cu(move, where) {
+ move.carry_british = count_unmoved_british_cu(where)
+ if (move.carry_british > 5)
+ move.carry_british = 5
+ move.carry_american = 0
+ move.carry_french = 0
}
-function pickup_max_american_cu(where) {
- game.carry_british = 0
- game.carry_french = count_unmoved_french_cu(where)
- game.carry_american = count_unmoved_american_cu(where)
- if (game.carry_french > 5)
- game.carry_french = 5
- if (game.carry_american + game.carry_french > 5)
- game.carry_american = 5 - game.carry_french
+function pickup_max_american_cu(move, where) {
+ move.carry_british = 0
+ move.carry_french = count_unmoved_french_cu(where)
+ move.carry_american = count_unmoved_american_cu(where)
+ if (move.carry_french > 5)
+ move.carry_french = 5
+ if (move.carry_american + move.carry_french > 5)
+ move.carry_american = 5 - move.carry_french
}
function move_army(who, from, to) {
- game.count -= movement_cost(from, to)
- if (game.mobility && has_enemy_cu(to)) {
- game.mobility = false
- game.count -= 1
- }
- if (game.carry_british > 0)
- move_british_cu(from, to, game.carry_british)
- if (game.carry_american > 0)
- move_american_cu(from, to, game.carry_american)
- if (game.carry_french > 0)
- move_french_cu(from, to, game.carry_french)
+ game.move.count -= movement_cost(from, to)
+ if (game.move.mobility && has_enemy_cu(to)) {
+ game.move.mobility = false
+ game.move.count -= 1
+ }
+ if (game.move.carry_british > 0)
+ move_british_cu(from, to, game.move.carry_british)
+ if (game.move.carry_american > 0)
+ move_american_cu(from, to, game.move.carry_american)
+ if (game.move.carry_french > 0)
+ move_french_cu(from, to, game.move.carry_french)
move_general(who, to)
}
function intercept_army(who, from, to) {
- if (game.carry_british > 0)
- move_british_cu(from, to, game.carry_british)
- if (game.carry_american > 0)
- move_american_cu(from, to, game.carry_american)
- if (game.carry_french > 0)
- move_french_cu(from, to, game.carry_french)
+ if (game.intercept.carry_british > 0)
+ move_british_cu(from, to, game.intercept.carry_british)
+ if (game.intercept.carry_american > 0)
+ move_american_cu(from, to, game.intercept.carry_american)
+ if (game.intercept.carry_french > 0)
+ move_french_cu(from, to, game.intercept.carry_french)
move_general(who, to)
}
@@ -935,7 +942,7 @@ function surrender_british_army(where) {
let g = find_british_general(where)
if (g)
capture_british_general(where)
- game.british_losses += count_british_cu(where)
+ game.combat.british_losses += count_british_cu(where)
remove_british_cu(where, count_british_cu(where))
}
@@ -1031,27 +1038,28 @@ function goto_committees_of_correspondence() {
logbr()
game.active = P_AMERICA
game.state = "committees_of_correspondence"
- game.coc = THE_13_COLONIES.slice()
+ game.colonies = THE_13_COLONIES.slice()
}
states.committees_of_correspondence = {
inactive: "Committees of Correspondence",
prompt() {
view.prompt =
- "Committees of Correspondence: Place 1 PC marker in each of the 13 colonies. " + game.coc.length + " left."
- if (game.coc.length > 0)
- gen_place_american_pc_in(game.coc)
+ "Committees of Correspondence: Place 1 PC marker in each of the 13 colonies. " + game.colonies.length + " left."
+ if (game.colonies.length > 0)
+ gen_place_american_pc_in(game.colonies)
else
gen_pass()
},
place_american_pc(space) {
push_undo()
let colony = SPACES[space].colony
- set_delete(game.coc, colony)
+ set_delete(game.colonies, colony)
place_american_pc(space)
},
pass() {
clear_undo()
+ delete game.colonies
goto_for_the_king()
},
}
@@ -1060,7 +1068,6 @@ function goto_for_the_king() {
logbr()
log(".h2.british For the King")
logbr()
- delete game.coc
game.active = P_BRITAIN
game.state = "for_the_king"
game.count = 3
@@ -1196,7 +1203,7 @@ states.british_declare_first = {
}
},
card_campaign(c) {
- delete game.congress_was_dispersed
+ game.congress_was_dispersed = false
logp("went first by playing a campaign card")
game.active = P_BRITAIN
goto_campaign(c)
@@ -1207,7 +1214,7 @@ states.british_declare_first = {
else
game.active = P_AMERICA
game.state = "choose_first_player"
- delete game.congress_was_dispersed
+ game.congress_was_dispersed = false
},
}
@@ -1259,7 +1266,7 @@ states.strategy_phase = {
},
card_discard_event(c) {
push_undo()
- game.did_discard_event = 0
+ game.did_discard_event = c
clear_queue()
discard_card(c, "PC action")
game.state = "discard_event_pc_action"
@@ -1294,7 +1301,7 @@ states.strategy_phase = {
exchange_for_discard(c) {
let d = game.did_discard_event = 0
game.did_discard_event = 0
- discard_card(c)
+ discard_card(c, "exchange")
set_add(active_hand(), d)
logp("picked up up #" + d)
},
@@ -1321,7 +1328,6 @@ function end_strategy_card() {
log("The French signed an alliance with the Americans!")
game.french_alliance_triggered = true
if (game.french_navy === -1) {
- game.save_active = game.active
game.active = P_AMERICA
game.state = "place_french_navy_trigger"
return
@@ -1572,7 +1578,7 @@ states.ops_british_reinforcements_who = {
pass() {
push_undo()
game.state = "ops_british_reinforcements_where"
- game.who = NOBODY
+ delete game.who
},
}
@@ -1591,7 +1597,7 @@ states.ops_british_reinforcements_where = {
place_reinforcements(space) {
place_british_reinforcements(game.who, game.count, space)
end_strategy_card()
- game.who = NOBODY
+ delete game.who
},
}
@@ -1609,7 +1615,7 @@ states.ops_american_reinforcements_who = {
pass() {
push_undo()
game.state = "ops_american_reinforcements_where"
- game.who = NOBODY
+ delete game.who
},
}
@@ -1624,7 +1630,7 @@ states.ops_american_reinforcements_where = {
else
place_american_reinforcements(game.who, game.count, space)
end_strategy_card()
- game.who = NOBODY
+ delete game.who
},
}
@@ -1676,7 +1682,7 @@ function gen_american_reinforcements_where(general) {
/* PLAY OPS CARD TO MOVE A GENERAL */
function goto_ops_general(c) {
- play_card(c, " to activate a general")
+ play_card(c, "to activate a general")
if (game.active === P_BRITAIN) {
game.count = CARDS[c].count + game.b_queue
game.b_queue = 0
@@ -1829,52 +1835,65 @@ function gen_remove_american_general() {
function goto_ops_general_move(g, marblehead) {
game.state = "ops_general_move"
- game.who = g
+
+ let where = location_of_general(g)
+
+ game.move = {
+ who: g,
+ from: where,
+ to: where,
+ count: 0,
+ mobility: false,
+ carry_british: 0,
+ carry_american: 0,
+ carry_french: 0
+ }
+
if (marblehead) {
- game.mobility = false
- game.count = 6
+ game.move.mobility = false
+ game.move.count = 6
} else {
if (game.active === P_BRITAIN) {
- game.mobility = false
- game.count = 4
+ game.move.mobility = false
+ game.move.count = 4
} else {
- game.mobility = true
- game.count = 5
+ game.move.mobility = true
+ game.move.count = 5
}
}
- let where = location_of_general(g)
+
if (game.active === P_BRITAIN)
- pickup_max_british_cu(where)
+ pickup_max_british_cu(game.move, where)
else
- pickup_max_american_cu(where)
+ pickup_max_american_cu(game.move, where)
}
states.ops_general_move = {
prompt() {
- view.prompt = "Move " + game.who + " with "
- if (game.carry_british > 0) {
- view.prompt += game.carry_british + " British CU."
- } else if (game.carry_french + game.carry_american > 0) {
- if (game.carry_french > 0) {
- if (game.carry_american > 0) {
- view.prompt += game.carry_french + " French CU and "
- view.prompt += game.carry_american + " American CU."
+ view.prompt = "Move " + game.move.who + " with "
+ if (game.move.carry_british > 0) {
+ view.prompt += game.move.carry_british + " British CU."
+ } else if (game.move.carry_french + game.move.carry_american > 0) {
+ if (game.move.carry_french > 0) {
+ if (game.move.carry_american > 0) {
+ view.prompt += game.move.carry_french + " French CU and "
+ view.prompt += game.move.carry_american + " American CU."
} else {
- view.prompt += game.carry_french + " French CU."
+ view.prompt += game.move.carry_french + " French CU."
}
} else {
- view.prompt += game.carry_american + " American CU."
+ view.prompt += game.move.carry_american + " American CU."
}
} else {
- view.prompt += game.carry_american + " no CU."
+ view.prompt += game.move.carry_american + " no CU."
}
if (game.count === 1)
- view.prompt += " " + game.count + " move left."
+ view.prompt += " " + game.move.count + " move left."
else if (game.count > 1)
- view.prompt += " " + game.count + " moves left."
+ view.prompt += " " + game.move.count + " moves left."
// Cannot stop on enemy general
- if (!has_enemy_general(location_of_general(game.who)))
+ if (!has_enemy_general(location_of_general(game.move.who)))
gen_pass()
gen_carry_cu()
@@ -1882,40 +1901,40 @@ states.ops_general_move = {
},
pickup_british_cu() {
- ++game.carry_british
+ ++game.move.carry_british
},
pickup_american_cu() {
- ++game.carry_american
+ ++game.move.carry_american
},
pickup_french_cu() {
- ++game.carry_french
+ ++game.move.carry_french
},
drop_british_cu() {
push_undo()
- --game.carry_british
- if (has_general_moved(game.who))
- mark_moved_british_cu(location_of_general(game.who), 1)
+ --game.move.carry_british
+ if (has_general_moved(game.move.who))
+ mark_moved_british_cu(location_of_general(game.move.who), 1)
},
drop_american_cu() {
push_undo()
- --game.carry_american
- if (has_general_moved(game.who))
- mark_moved_american_cu(location_of_general(game.who), 1)
+ --game.move.carry_american
+ if (has_general_moved(game.move.who))
+ mark_moved_american_cu(location_of_general(game.move.who), 1)
},
drop_french_cu() {
push_undo()
- --game.carry_french
- if (has_general_moved(game.who))
- mark_moved_french_cu(location_of_general(game.who), 1)
+ --game.move.carry_french
+ if (has_general_moved(game.move.who))
+ mark_moved_french_cu(location_of_general(game.move.who), 1)
},
move(to) {
push_undo()
- set_general_moved(game.who)
- let from = location_of_general(game.who)
- let cu = game.carry_british + game.carry_american + game.carry_french
+ set_general_moved(game.move.who)
+ let from = location_of_general(game.move.who)
+ let cu = game.move.carry_british + game.move.carry_american + game.move.carry_french
let intercept = false
if (game.active === P_BRITAIN) {
@@ -1924,7 +1943,10 @@ states.ops_general_move = {
intercept = can_intercept_to(to)
}
- move_army(game.who, from, to)
+ game.move.from = from
+ game.move.to = to
+
+ move_army(game.move.who, from, to)
if (cu > 0) {
if (has_enemy_general(to) && !has_enemy_cu(to)) {
@@ -1939,13 +1961,13 @@ states.ops_general_move = {
}
if (intercept)
- goto_intercept(from, to)
+ goto_intercept()
else
- resume_moving(from, to)
+ resume_moving()
},
pass() {
clear_undo()
- let where = location_of_general(game.who)
+ let where = location_of_general(game.move.who)
end_move()
if (count_friendly_generals(where) > 1)
goto_remove_general(where)
@@ -1954,10 +1976,10 @@ states.ops_general_move = {
},
}
-function resume_moving(from, to) {
- if (has_enemy_cu(to)) {
+function resume_moving() {
+ if (has_enemy_cu(game.move.to)) {
end_move()
- goto_start_battle(from, to)
+ goto_start_battle()
}
}
@@ -1973,7 +1995,7 @@ function can_intercept_to(to) {
}
function gen_intercept() {
- for (let space of SPACES[game.where].adjacent) {
+ for (let space of SPACES[game.move.to].adjacent) {
if (has_american_army(space)) {
let g = find_american_or_french_general(space)
if (g && !has_general_moved(g))
@@ -1982,19 +2004,15 @@ function gen_intercept() {
}
}
-function goto_intercept(from, where) {
+function goto_intercept() {
clear_undo()
- game.save_who = game.who
- game.who = NOBODY
- game.from = from
- game.where = where
game.active = P_AMERICA
game.state = "intercept"
}
states.intercept = {
prompt() {
- view.prompt = "Intercept " + game.save_who + " in " + game.where + "?"
+ view.prompt = "Intercept " + game.move.who + " in " + game.move.to + "?"
gen_pass()
gen_intercept()
},
@@ -2003,26 +2021,28 @@ states.intercept = {
let die = roll_d6()
if (die <= GENERALS[g].agility) {
log(g + " intercepted (" + die + " <= " + GENERALS[g].agility + ")")
- game.did_intercept = 1
-
- let save_carry_british = game.carry_british
- let save_carry_american = game.carry_american
- let save_carry_french = game.carry_french
-
- pickup_max_american_cu(location_of_general(g))
- intercept_army(g, location_of_general(g), game.where)
+ game.move.did_intercept = 1
+
+ game.intercept = {
+ who: g,
+ from: location_of_general(g),
+ to: game.move.to,
+ carry_british: 0,
+ carry_american: 0,
+ carry_french: 0,
+ }
- game.carry_british = save_carry_british
- game.carry_american = save_carry_american
- game.carry_french = save_carry_french
+ pickup_max_american_cu(game.intercept, location_of_general(g))
+ intercept_army(g, location_of_general(g), game.move.to)
- if (count_friendly_generals(game.where) > 1)
+ if (count_friendly_generals(game.move.to) > 1)
goto_remove_general_after_intercept()
else
end_intercept()
} else {
log(g + " failed to intercept (" + die + " > " + GENERALS[g].agility + ")")
- if (!can_intercept_to(game.where))
+ delete game.intercept
+ if (!can_intercept_to(game.move.to))
end_intercept()
}
},
@@ -2034,24 +2054,18 @@ states.intercept = {
function end_intercept() {
game.active = P_BRITAIN
game.state = "ops_general_move"
- game.who = game.save_who
- delete game.save_who
- resume_moving(game.from, game.where)
- delete game.from
+ delete game.intercept
+ resume_moving()
}
function end_move() {
- let where = location_of_general(game.who)
- if (has_general_moved(game.who)) {
- mark_moved_british_cu(where, game.carry_british)
- mark_moved_american_cu(where, game.carry_american)
- mark_moved_french_cu(where, game.carry_french)
+ let where = location_of_general(game.move.who)
+ if (has_general_moved(game.move.who)) {
+ mark_moved_british_cu(where, game.move.carry_british)
+ mark_moved_american_cu(where, game.move.carry_american)
+ mark_moved_french_cu(where, game.move.carry_french)
}
- game.who = NOBODY
- delete game.mobility
- delete game.carry_british
- delete game.carry_american
- delete game.carry_french
+ delete game.move
}
function path_type(from, to) {
@@ -2063,21 +2077,21 @@ function path_type(from, to) {
}
function gen_carry_cu() {
- let where = location_of_general(game.who)
+ let where = location_of_general(game.move.who)
if (game.active === P_BRITAIN) {
- if (game.carry_british > 0)
+ if (game.move.carry_british > 0)
gen_action("drop_british_cu")
- if (game.carry_british < 5 && game.carry_british < count_unmoved_british_cu(where))
+ if (game.move.carry_british < 5 && game.move.carry_british < count_unmoved_british_cu(where))
gen_action("pickup_british_cu")
} else {
- let carry_total = game.carry_french + game.carry_american
- if (game.carry_french > 0)
+ let carry_total = game.move.carry_french + game.move.carry_american
+ if (game.move.carry_french > 0)
gen_action("drop_french_cu")
- if (game.carry_american > 0)
+ if (game.move.carry_american > 0)
gen_action("drop_american_cu")
- if (carry_total < 5 && game.carry_french < count_unmoved_french_cu(where))
+ if (carry_total < 5 && game.move.carry_french < count_unmoved_french_cu(where))
gen_action("pickup_french_cu")
- if (carry_total < 5 && game.carry_american < count_unmoved_american_cu(where))
+ if (carry_total < 5 && game.move.carry_american < count_unmoved_american_cu(where))
gen_action("pickup_american_cu")
}
}
@@ -2096,13 +2110,13 @@ function movement_cost(from, to) {
}
function gen_move_general() {
- let from = location_of_general(game.who)
- let alone = game.carry_british + game.carry_american + game.carry_french === 0
+ let from = location_of_general(game.move.who)
+ let alone = game.move.carry_british + game.move.carry_american + game.move.carry_french === 0
for (let to of SPACES[from].adjacent) {
let mp = 1
if (path_type(from, to) === "wilderness") {
if ((from === QUEBEC && to === FALMOUTH) || (to === QUEBEC && from === FALMOUTH))
- if (game.who !== ARNOLD)
+ if (game.move.who !== ARNOLD)
continue
mp = 3
}
@@ -2117,11 +2131,11 @@ function gen_move_general() {
continue
}
- if (game.mobility && has_enemy_cu(to)) {
- if (game.count - mp >= 1)
+ if (game.move.mobility && has_enemy_cu(to)) {
+ if (game.move.count - mp >= 1)
gen_action("move", to)
} else {
- if (game.count - mp >= 0)
+ if (game.move.count - mp >= 0)
gen_action("move", to)
}
}
@@ -2409,7 +2423,7 @@ events.lord_sandwich_coastal_raids = function (c, card) {
play_card(c)
game.state = "lord_sandwich_coastal_raids"
game.count = 2
- game.where = NOWHERE
+ delete game.where
}
states.lord_sandwich_coastal_raids = {
@@ -2507,7 +2521,7 @@ events.pennsylvania_and_new_jersey_line_mutinies = function (c, card) {
game.pennsylvania_and_new_jersey_line_mutinies = true
game.state = "pennsylvania_and_new_jersey_line_mutinies"
game.count = 2
- game.where = NOWHERE
+ delete game.where
}
states.pennsylvania_and_new_jersey_line_mutinies = {
@@ -2556,24 +2570,24 @@ states.john_glovers_marblehead_regiment_who = {
events.declaration_of_independence = function (c, card) {
play_card(c)
- game.last_active = game.active
+ game.save = game.active
game.active = P_AMERICA
- game.doi = THE_13_COLONIES.slice()
+ game.colonies = THE_13_COLONIES.slice()
game.state = "declaration_of_independence"
}
states.declaration_of_independence = {
prompt() {
view.prompt = "Declaration of Independence: Place 1 PC marker in each of the 13 colonies. "
- view.prompt += game.doi.length + " left."
+ view.prompt += game.colonies.length + " left."
gen_pass()
- gen_place_american_pc_in(game.doi)
+ gen_place_american_pc_in(game.colonies)
},
place_american_pc(space) {
let colony = SPACES[space].colony
- set_delete(game.doi, colony)
+ set_delete(game.colonies, colony)
place_american_pc(space)
- if (game.doi.length === 0)
+ if (game.colonies.length === 0)
end_declaration_of_independence()
},
pass() {
@@ -2582,17 +2596,21 @@ states.declaration_of_independence = {
}
function end_declaration_of_independence() {
- game.active = game.last_active
- delete game.last_active
- delete game.doi
+ game.active = game.save
+ delete game.save
+ delete game.colonies
end_strategy_card()
}
function goto_george_washington_captured() {
+ // TODO: this is not robust enough! figure out exactly where we are called.
+
/* Save all the state we clobber during the interrupt. */
- game.last_state = game.state
- game.last_active = game.active
- game.last_count = game.count
+ game.save = {
+ state: game.state,
+ active: game.active,
+ count: game.count
+ }
game.state = "george_washington_captured"
game.active = P_BRITAIN
@@ -2618,12 +2636,10 @@ states.george_washington_captured = {
function end_george_washington_captured() {
/* Restore previous state. */
- game.state = game.last_state
- game.count = game.last_count
- game.active = game.last_active
- delete game.last_state
- delete game.last_active
- delete game.last_count
+ game.state = game.save.state
+ game.count = game.save.count
+ game.active = game.save.active
+ delete game.save
}
function do_event(c) {
@@ -2636,25 +2652,29 @@ function do_event(c) {
/* BATTLE */
-function can_retreat_before_battle(where) {
- if (game.did_intercept)
+function can_retreat_before_battle() {
+ if (game.move.did_intercept)
return false
// can't retreat if attempted (successful or not) interception!
- let g = find_american_or_french_general(where)
+ let g = find_american_or_french_general(game.move.to)
if (g && !has_general_moved(g))
return true
return false
}
-function goto_start_battle(from, where) {
+function goto_start_battle() {
clear_undo()
- game.attacker = game.active
- game.attack_from = from
- game.british_losses = 0
- game.where = where
- game.a_bonus = 0
- game.b_bonus = 0
- if (game.active === P_BRITAIN && can_retreat_before_battle(where))
+
+ game.combat = {
+ attacker: game.active,
+ a_bonus: 0,
+ b_bonus: 0,
+ b_draw_after_battle: false,
+ a_draw_after_battle: false,
+ british_losses: 0,
+ }
+
+ if (game.active === P_BRITAIN && can_retreat_before_battle())
goto_retreat_before_battle()
else
goto_play_attacker_battle_card()
@@ -2662,7 +2682,7 @@ function goto_start_battle(from, where) {
function goto_retreat_before_battle() {
game.active = P_AMERICA
- game.who = find_american_or_french_general(game.where)
+ game.who = find_american_or_french_general(game.move.to)
game.state = "retreat_before_battle"
}
@@ -2679,8 +2699,8 @@ states.retreat_before_battle = {
let roll = roll_d6()
if (roll <= agility) {
logp("successfully retreated before battle: " + roll + " <= " + agility)
- pickup_max_american_cu(game.where)
- move_army(game.who, game.where, to)
+ pickup_max_american_cu(game.move.to)
+ move_army(game.who, game.move.to, to)
goto_remove_general_after_retreat_before_battle(to)
} else {
logp("failed to retreat before battle: " + roll + " > " + agility)
@@ -2692,11 +2712,10 @@ states.retreat_before_battle = {
},
}
-function goto_remove_general_after_retreat_before_battle(to) {
- if (count_friendly_generals(to) > 1) {
+function goto_remove_general_after_retreat_before_battle(where) {
+ if (count_friendly_generals(where) > 1) {
game.state = "remove_general_after_retreat_before_battle"
- game.save_where = game.where
- game.where = to
+ game.where = where
} else {
end_remove_general_after_retreat_before_battle()
}
@@ -2712,19 +2731,17 @@ states.remove_general_after_retreat_before_battle = {
move_general(g, BRITISH_REINFORCEMENTS)
else
move_general(g, AMERICAN_REINFORCEMENTS)
- game.where = game.save_where
- delete game.save_where
end_remove_general_after_retreat_before_battle()
},
}
function end_remove_general_after_retreat_before_battle() {
- let b_cu = count_british_cu(game.where)
- let a_cu = count_american_and_french_cu(game.where)
+ let b_cu = count_british_cu(game.move.to)
+ let a_cu = count_american_and_french_cu(game.move.to)
if (a_cu === 0) {
end_battle()
} else if (b_cu >= 4 && a_cu === 1) {
- overrun(game.where)
+ overrun(game.move.to)
end_battle()
} else {
end_retreat_before_battle()
@@ -2732,7 +2749,7 @@ function end_remove_general_after_retreat_before_battle() {
}
function can_defender_retreat(to) {
- if (to === game.attack_from)
+ if (to === game.move.from)
return false
if (has_enemy_pc(to))
return false
@@ -2742,7 +2759,7 @@ function can_defender_retreat(to) {
}
function can_attacker_retreat() {
- let to = game.attack_from
+ let to = game.move.from
if (has_enemy_pc(to))
return false
if (has_enemy_cu(to))
@@ -2751,7 +2768,7 @@ function can_attacker_retreat() {
}
function gen_defender_retreat() {
- let from = game.where
+ let from = game.move.to
for (let to of SPACES[from].adjacent) {
if (can_defender_retreat(to))
gen_action("move", to)
@@ -2780,16 +2797,16 @@ function gen_defender_retreat() {
function gen_attacker_retreat() {
if (can_attacker_retreat())
- gen_action("move", game.attack_from)
+ gen_action("move", game.move.from)
}
function end_retreat_before_battle() {
- game.who = NOBODY
+ delete game.who
goto_play_attacker_battle_card()
}
function goto_play_attacker_battle_card() {
- game.active = game.attacker
+ game.active = game.combat.attacker
game.state = "play_attacker_battle_card"
}
@@ -2804,22 +2821,22 @@ states.play_attacker_battle_card = {
if (game.active === P_BRITAIN) {
if (CARDS[c].event === "remove_benedict_arnold")
remove_benedict_arnold()
- game.b_draw_after_battle = true
- game.b_bonus += 2
+ game.combat.b_draw_after_battle = true
+ game.combat.b_bonus += 2
} else {
- game.a_draw_after_battle = true
- game.a_bonus += 2
+ game.combat.a_draw_after_battle = true
+ game.combat.a_bonus += 2
}
goto_play_defender_battle_card()
},
card_battle_discard(c) {
discard_card(c, "for +1 DRM")
if (game.active === P_BRITAIN) {
- game.b_draw_after_battle = true
- game.b_bonus += 1
+ game.combat.b_draw_after_battle = true
+ game.combat.b_bonus += 1
} else {
- game.a_draw_after_battle = true
- game.a_bonus += 1
+ game.combat.a_draw_after_battle = true
+ game.combat.a_bonus += 1
}
goto_play_defender_battle_card()
},
@@ -2830,7 +2847,7 @@ states.play_attacker_battle_card = {
function goto_play_defender_battle_card() {
game.state = "play_defender_battle_card"
- game.active = ENEMY[game.attacker]
+ game.active = ENEMY[game.combat.attacker]
}
states.play_defender_battle_card = {
@@ -2844,22 +2861,22 @@ states.play_defender_battle_card = {
if (game.active === P_BRITAIN) {
if (CARDS[c].event === "remove_benedict_arnold")
remove_benedict_arnold()
- game.b_draw_after_battle = true
- game.b_bonus += 2
+ game.combat.b_draw_after_battle = true
+ game.combat.b_bonus += 2
} else {
- game.a_draw_after_battle = true
- game.a_bonus += 2
+ game.combat.a_draw_after_battle = true
+ game.combat.a_bonus += 2
}
resolve_battle()
},
card_battle_discard(c) {
discard_card(c, "for +1 DRM")
if (game.active === P_BRITAIN) {
- game.b_draw_after_battle = true
- game.b_bonus += 1
+ game.combat.b_draw_after_battle = true
+ game.combat.b_bonus += 1
} else {
- game.a_draw_after_battle = true
- game.a_bonus += 1
+ game.combat.a_draw_after_battle = true
+ game.combat.a_bonus += 1
}
resolve_battle()
},
@@ -2944,20 +2961,20 @@ function roll_winner_combat_losses(log, losing_general) {
}
function apply_british_combat_losses(max) {
- let n = Math.min(count_british_cu(game.where), max)
- remove_british_cu(game.where, n)
+ let n = Math.min(count_british_cu(game.move.to), max)
+ remove_british_cu(game.move.to, n)
return n
}
function apply_american_combat_losses(max) {
- let n = Math.min(count_american_cu(game.where), max)
- remove_american_cu(game.where, n)
+ let n = Math.min(count_american_cu(game.move.to), max)
+ remove_american_cu(game.move.to, n)
return n
}
function apply_french_combat_losses(max) {
- let n = Math.min(count_french_cu(game.where), max)
- remove_french_cu(game.where, n)
+ let n = Math.min(count_french_cu(game.move.to), max)
+ remove_french_cu(game.move.to, n)
return n
}
@@ -2973,10 +2990,10 @@ function resolve_battle() {
let b_log = []
game.active = ENEMY[game.active]
- let b_g = find_british_general(game.where)
- let b_cu = count_british_cu(game.where)
- let a_g = find_american_or_french_general(game.where)
- let a_cu = count_american_and_french_cu(game.where)
+ let b_g = find_british_general(game.move.to)
+ let b_cu = count_british_cu(game.move.to)
+ let a_g = find_american_or_french_general(game.move.to)
+ let a_cu = count_american_and_french_cu(game.move.to)
let b_br = 0
let a_br = 0
@@ -3008,14 +3025,14 @@ function resolve_battle() {
b_log.push("+" + b_br + " Actual Battle Rating")
a_log.push("+" + a_br + " Actual Battle Rating")
- let b_drm = b_cu + b_br + game.b_bonus
+ let b_drm = b_cu + b_br + game.combat.b_bonus
if (game.regulars) {
b_log.push("+1 British Regulars' Advantage")
b_drm += 1
}
- if (is_non_blockaded_port(game.where)) {
- if (is_fortified_port(game.where)) {
- if (has_british_pc(game.where)) {
+ if (is_non_blockaded_port(game.move.to)) {
+ if (is_fortified_port(game.move.to)) {
+ if (has_british_pc(game.move.to)) {
b_log.push("+1 Royal Navy Support")
b_drm += 1
}
@@ -3024,17 +3041,17 @@ function resolve_battle() {
b_drm += 1
}
}
- if (is_british_militia(game.where)) {
+ if (is_british_militia(game.move.to)) {
b_log.push("+1 Militia")
b_drm += 1
}
- if (game.b_bonus === 2)
+ if (game.combat.b_bonus === 2)
b_log.push("+2 Battle Card")
- else if (game.b_bonus === 1)
+ else if (game.combat.b_bonus === 1)
b_log.push("+1 Discard of an Event Card")
- let a_drm = a_cu + a_br + game.a_bonus
- if (is_american_militia(game.where)) {
+ let a_drm = a_cu + a_br + game.combat.a_bonus
+ if (is_american_militia(game.move.to)) {
a_log.push("+1 Militia")
a_drm += 1
}
@@ -3042,11 +3059,11 @@ function resolve_battle() {
a_log.push("+2 American Winter Offensive")
a_drm += 2
}
- if (game.a_bonus === 2)
+ if (game.combat.a_bonus === 2)
a_log.push("+2 Battle Card")
- else if (game.a_bonus === 1)
+ else if (game.combat.a_bonus === 1)
a_log.push("+1 Discard of an Event Card")
- if (game.did_intercept) {
+ if (game.move.did_intercept) {
a_log.push("+1 Interception")
a_drm += 1
}
@@ -3074,24 +3091,24 @@ function resolve_battle() {
a_lost_cu = roll_winner_combat_losses(a_log, b_g)
}
- game.british_losses = apply_british_combat_losses(b_lost_cu)
+ game.combat.british_losses = apply_british_combat_losses(b_lost_cu)
let american_losses = apply_american_and_french_combat_losses(a_lost_cu)
- b_log.push("Losses: " + game.british_losses + " CU")
+ b_log.push("Losses: " + game.combat.british_losses + " CU")
a_log.push("Losses: " + american_losses + " CU")
// Special case: winning general with no CU on enemy PC is captured
if (victor === P_BRITAIN) {
- if (b_g && count_british_cu(game.where) === 0 && has_american_pc(game.where))
- capture_british_general(game.where)
+ if (b_g && count_british_cu(game.move.to) === 0 && has_american_pc(game.move.to))
+ capture_british_general(game.move.to)
} else {
- if (a_g && count_american_and_french_cu(game.where) === 0 && has_british_pc(game.where))
- capture_american_or_french_general(game.where)
+ if (a_g && count_american_and_french_cu(game.move.to) === 0 && has_british_pc(game.move.to))
+ capture_american_or_french_general(game.move.to)
}
log("BRITISH BATTLE REPORT:\n" + b_log.join("\n"))
log("AMERICAN BATTLE REPORT:\n" + a_log.join("\n"))
- log(victor + " victory in " + game.where + "!")
+ log(victor + " victory in " + game.move.to + "!")
if (victor === P_AMERICA)
advance_french_alliance(1)
@@ -3101,12 +3118,12 @@ function resolve_battle() {
function goto_retreat_after_battle(victor) {
if (victor === P_BRITAIN) {
- game.who = find_american_or_french_general(game.where)
- if (game.who === NOBODY && count_american_and_french_cu(game.where) === 0)
+ game.who = find_american_or_french_general(game.move.to)
+ if (game.who === NOBODY && count_american_and_french_cu(game.move.to) === 0)
return end_battle()
} else {
- game.who = find_british_general(game.where)
- if (game.who === NOBODY && count_british_cu(game.where) === 0)
+ game.who = find_british_general(game.move.to)
+ if (game.who === NOBODY && count_british_cu(game.move.to) === 0)
return end_battle()
}
game.active = ENEMY[victor]
@@ -3117,7 +3134,7 @@ states.retreat_after_battle = {
prompt() {
view.prompt = "Retreat after battle."
gen_action("surrender")
- if (game.active === game.attacker)
+ if (game.active === game.combat.attacker)
gen_attacker_retreat()
else
gen_defender_retreat()
@@ -3125,9 +3142,9 @@ states.retreat_after_battle = {
move(to) {
logp("retreated to " + to)
if (game.active === P_BRITAIN)
- retreat_british_army(game.where, to)
+ retreat_british_army(game.move.to, to)
else
- retreat_american_army(game.where, to)
+ retreat_american_army(game.move.to, to)
if (count_friendly_generals(to) > 1)
goto_remove_general_after_retreat(to)
else
@@ -3136,42 +3153,34 @@ states.retreat_after_battle = {
surrender() {
// End battle here, so if Washington is captured we can handle the interrupt state.
let active = game.active
- let where = game.where
+ // TODO: ugly clean this up
end_battle()
logp("surrendered")
if (active === P_BRITAIN)
- surrender_british_army(where)
+ surrender_british_army(game.move.to)
else
- surrender_american_army(where)
+ surrender_american_army(game.move.to)
},
}
function end_battle() {
- game.active = game.attacker
+ game.active = game.combat.attacker
- if (game.active === P_BRITAIN && game.congress === game.where)
+ if (game.active === P_BRITAIN && game.congress === game.move.to)
disperse_continental_congress()
- if (game.british_losses >= 3)
+ if (game.combat.british_losses >= 3)
lose_regular_advantage()
// TODO: delay until end of campaign
- if (game.b_draw_after_battle)
+ if (game.combat.b_draw_after_battle)
set_add(game.b_hand, deal_card())
- if (game.a_draw_after_battle)
+ if (game.combat.a_draw_after_battle)
set_add(game.a_hand, deal_card())
- delete game.did_intercept
- delete game.b_bonus
- delete game.a_bonus
- delete game.b_draw_after_battle
- delete game.a_draw_after_battle
- delete game.attack_from
- delete game.british_losses
- delete game.attacker
- game.where = NOWHERE
- game.who = NOBODY
+ delete game.combat
+ delete game.move
end_strategy_card()
}
@@ -3250,6 +3259,7 @@ function goto_winter_attrition_phase() {
function goto_french_naval_phase() {
if (game.french_navy !== -1) {
+ game.save = game.active
game.active = P_AMERICA
game.state = "place_french_navy"
} else {
@@ -3275,8 +3285,8 @@ states.place_french_navy_trigger = {
place_navy(zone) {
logp("placed French Navy.")
game.french_navy = zone
- game.active = game.save_active
- delete game.save_active
+ game.active = game.save
+ delete game.save
end_strategy_card()
},
}
@@ -3516,6 +3526,10 @@ function gen_action(action, argument) {
}
}
+function gen_pass() {
+ gen_action("pass")
+}
+
exports.scenarios = [ "Standard" ]
exports.roles = [ P_BRITAIN, P_AMERICA ]
@@ -3559,8 +3573,8 @@ exports.view = function (state, current) {
french_navy: state.french_navy,
regulars: state.regulars,
- loc: state.loc,
- spc: state.spc,
+ loca: state.loca,
+ cupc: state.cupc,
a_cards: state.a_hand.length,
b_cards: state.b_hand.length,