summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js819
1 files changed, 455 insertions, 364 deletions
diff --git a/rules.js b/rules.js
index 0d3b55e..b492c23 100644
--- a/rules.js
+++ b/rules.js
@@ -89,6 +89,8 @@ function is_gray_indian(p) { return (p >= 16 && p <= 20) || (p >= 108 && p <= 11
function is_cherokee(p) { return (p >= 14 && p <= 15) }
function is_mohawk(p) { return (p >= 21 && p <= 22) }
function is_british_iroquois_or_mohawk(p) { return (p >= 16 && p <= 22) }
+function is_british_leader(p) { return p >= 1 && p <= 13 }
+function is_french_leader(p) { return p >= 87 && p <= 96 }
const AMHERST = 1
const BRADDOCK = 2
const ABERCROMBY = 3
@@ -200,10 +202,6 @@ for (let s = first_space; s <= last_space; ++s) {
spaces.forEach(ss => ss.nb_name = ss.name.replace(/ /g, '\xa0'))
// GLOBALS
-pieces.forEach(pp => {
- if (pp.desc) pp.nb_desc = pp.desc.replace(/ /g, '\xa0')
- if (pp.rdesc) pp.nb_rdesc = pp.rdesc.replace(/ /g, '\xa0')
-})
let game
let view = null
@@ -239,20 +237,15 @@ function random(n) {
return (game.seed = game.seed * 200105 % 34359738337) % n
}
-function roll_die(reason) {
- let die = random(6) + 1
- if (reason)
- log(`Rolled ${die} ${reason}.`)
- else
- log(`Rolled ${die}.`)
- return die
+function roll_die() {
+ return random(6) + 1
}
function modify(die, drm, why) {
if (drm >= 0)
- log(`+${drm} ${why}.`)
+ log(`>+${drm} ${why}`)
else if (drm < 0)
- log(`${drm} ${why}.`)
+ log(`>\u2212${-drm} ${why}`)
return die + drm
}
@@ -275,84 +268,96 @@ function log(msg) {
game.log.push(msg)
}
-function push_summary(summary, p) {
- let s = piece_space(p)
- if (!(s in summary))
- summary[s] = []
- summary[s].push(piece_name(p))
+function map_get_set(map, key) {
+ let set = map_get(map, key)
+ if (!set)
+ map_set(map, key, set = [])
+ return set
}
-function print_plain_summary(verb, list) {
- if (game.summary) {
- if (game.summary[list].length > 0)
- log(verb + "\n" + game.summary[list].sort((a,b)=>a-b).map(piece_name).join(",\n") + ".")
- delete game.summary[list]
- }
+function push_summary(summary, p) {
+ set_add(map_get_set(summary, piece_space(p)), p)
}
-function print_summary(summary, verb) {
- for (let s in summary)
- log(verb + "%" + s + "\n" + summary[s].join(",\n") + ".")
+function push_retreat_summary(p, s) {
+ set_add(map_get_set(game.summary.retreat, s), p)
}
-function flush_summary() {
- if (game.summary) {
- print_summary(game.summary.placed, "Placed at ")
- print_summary(game.summary.restored, "Restored at ")
- print_summary(game.summary.reduced, "Reduced at ")
- print_summary(game.summary.eliminated, "Eliminated at ")
- game.summary.placed = {}
- game.summary.restored = {}
- game.summary.reduced = {}
- game.summary.eliminated = {}
+function make_summary(list) {
+ let result = []
+ let current = 0
+ let n = 0
+ for (let p of list) {
+ if (is_leader(p)) {
+ // leaders are always first
+ result.push("P" + p)
+ continue
+ }
+ let name = piece_log_name(p)
+ if (name !== current) {
+ if (n > 0)
+ result.push(n + " " + current)
+ current = name
+ n = 1
+ } else {
+ ++n
+ }
}
+ if (n > 0)
+ result.push(n + " " + current)
+ return result.join("\n")
}
-function init_retreat_summary() {
- if (game.summary)
- game.summary.retreat = {}
+function print_plain_summary(verb, list) {
+ if (game.summary[list].length > 0)
+ log(verb + "\n" + make_summary(game.summary[list]))
+ delete game.summary[list]
}
-function push_retreat_summary(p, s) {
- if (game.summary) {
- if (!(s in game.summary.retreat))
- game.summary.retreat[s] = []
- game.summary.retreat[s].push(p)
- } else {
- // log(piece_name(p) + " retreated " + s + ".")
- log(piece_name(p) + " " + s + ".")
+function print_summary(summary, verb) {
+ if (summary.length > 0) {
+ log(verb)
+ map_for_each(summary, (s, list) => {
+ log(">%" + s + "\n" + make_summary(list))
+ })
}
}
-function flush_retreat_summary() {
- if (game.summary) {
- for (let s in game.summary.retreat)
- log("Retreated " + s + "\n" + game.summary.retreat[s].map(piece_name).join(",\n") + ".")
- delete game.summary.retreat
- }
+function print_summary_no_space(summary, verb) {
+ if (summary.length === 2)
+ log(verb + "\n" + make_summary(summary[1]))
+ else
+ print_summary(summary, verb)
}
-function init_go_home_summary() {
- if (game.summary)
- game.summary.go_home = {}
+function flush_summary() {
+ print_summary(game.summary.placed, "Placed")
+ print_summary(game.summary.restored, "Restored")
+ print_summary(game.summary.reduced, "Reduced")
+ print_summary(game.summary.eliminated, "Eliminated")
+ game.summary.placed = []
+ game.summary.restored = []
+ game.summary.reduced = []
+ game.summary.eliminated = []
}
-function push_go_home_summary(p, s) {
- if (game.summary) {
- if (!(s in game.summary.go_home))
- game.summary.go_home[s] = []
- game.summary.go_home[s].push(log_piece_name_and_place(p))
- } else {
- // log(log_piece_name_and_place(p) + " went home to %" + s + ".")
- log(log_piece_name_and_place(p) + " home to %" + s + ".")
- }
+function flush_losses_summary() {
+ print_summary_no_space(game.summary.reduced, "Reduced")
+ print_summary_no_space(game.summary.eliminated, "Eliminated")
+ game.summary.reduced = []
+ game.summary.eliminated = []
+}
+
+function flush_retreat_summary() {
+ map_for_each(game.summary.retreat, (s, list) => {
+ log(s + "\n" + make_summary(list))
+ })
+ delete game.summary.retreat
}
function flush_go_home_summary() {
- if (game.summary) {
- print_summary(game.summary.go_home, "Went home to ")
- delete game.summary.go_home
- }
+ print_summary(game.summary.go_home, "Went home")
+ delete game.summary.go_home
}
// CURRENT PLAYER ALIASES
@@ -723,7 +728,7 @@ function draw_leader_from_pool() {
let i = random(game.british.pool.length)
let p = game.british.pool[i]
- log(`Drew ${piece_name(p)} from pool.`)
+ log(`Drew P${p} from pool.`)
// 5.55 If both on-map 7 leaders are besieged, return the third to the pool without substitution.
if (is_seven_command_leader(p)) {
@@ -733,7 +738,7 @@ function draw_leader_from_pool() {
if (is_piece_on_map(BRADDOCK) && is_piece_inside(BRADDOCK)) ++n
if (is_piece_on_map(LOUDOUN) && is_piece_inside(LOUDOUN)) ++n
if (n >= 2) {
- log(`Returned ${piece_name(p)} to pool.`)
+ log(`Returned P${p} to pool.`)
return 0
}
}
@@ -933,20 +938,16 @@ function is_originally_enemy(s) {
return is_originally_british(s)
}
-function piece_name(p) {
- if (is_unit_reduced(p))
- return pieces[p].nb_rdesc
- return pieces[p].nb_desc
+function piece_log_name(p) {
+ return pieces[p].log_name
}
-function log_piece_name_and_place(p) {
- // return piece_name(p) + " at %" + piece_space(p)
- return piece_name(p) + " (%" + piece_space(p) + ")"
+function piece_name(p) {
+ return pieces[p].name || pieces[p].log_name
}
function piece_name_and_place(p) {
- // return piece_name(p) + " at %" + space_name(piece_space(p))
- return piece_name(p) + " (" + space_name(piece_space(p)) + ")"
+ return piece_name(p) + " at " + space_name(piece_space(p))
}
function piece_movement(p) {
@@ -977,6 +978,10 @@ function leader_tactics(p) {
return pieces[p].tactics
}
+function leader_tactics_text(who) {
+ return is_british_leader(who) ? "RB" + leader_tactics(who) : "RF" + leader_tactics(who)
+}
+
// DYNAMIC PROPERTIES
function piece_node(p) {
@@ -1143,20 +1148,15 @@ function has_fieldworks(s) {
}
function place_fieldworks(s) {
- log(`Placed fieldworks at %${s}.`)
set_add(game.fieldworks, s)
}
function remove_fieldworks(s) {
- if (set_has(game.fieldworks, s)) {
- // log(`Fieldworks (%${s}) removed.`)
- log(`Removed fieldworks at %${s}.`)
- set_delete(game.fieldworks, s)
- }
+ set_delete(game.fieldworks, s)
}
function place_friendly_raided_marker(s) {
- log(`Placed raided marker at %${s}.`)
+ log("Placed raided marker.")
player.raids.push(s)
player.raids.sort((a,b)=>a-b)
}
@@ -1676,14 +1676,14 @@ function find_enemy_commanding_leader_in_space(s) {
function log_vp(n) {
if (game.active === FRANCE) {
if (n < 0)
- log(`France lost ${-n} VP.`)
+ log(`France \u2212${-n} VP.`)
else
- log(`France gained ${n} VP.`)
+ log(`France +${n} VP.`)
} else {
if (n < 0)
- log(`Britain gained ${-n} VP.`)
+ log(`Britain +${-n} VP.`)
else
- log(`Britain lost ${n} VP.`)
+ log(`Britain \u2212${n} VP.`)
}
}
@@ -1751,39 +1751,21 @@ function unstack_piece_from_force(p) {
function restore_unit(p) {
set_unit_reduced(p, 0)
- if (game.summary && game.summary.restored)
- push_summary(game.summary.restored, p)
- else
- // log(`Restored ${log_piece_name_and_place(p)}.`)
- log(`${log_piece_name_and_place(p)} restored.`)
+ push_summary(game.summary.restored, p)
}
-function reduce_unit(p, verbose=true) {
+function reduce_unit(p) {
if (is_unit_reduced(p) || is_one_step_marine_detachment(p)) {
- eliminate_piece(p, verbose)
+ eliminate_piece(p)
return true
}
- if (game.summary && game.summary.reduced)
- push_summary(game.summary.reduced, p)
- else if (verbose)
- // log(`Reduced ${log_piece_name_and_place(p)}.`)
- log(`${log_piece_name_and_place(p)} reduced.`)
- else
- // log(`Reduced ${piece_name(p)}.`)
- log(`${piece_name(p)} reduced.`)
+ push_summary(game.summary.reduced, p)
set_unit_reduced(p, 1)
return false
}
-function eliminate_piece(p, verbose=true) {
- if (game.summary && game.summary.eliminated)
- push_summary(game.summary.eliminated, p)
- else if (verbose)
- // log(`Eliminated ${log_piece_name_and_place(p)}.`)
- log(`${log_piece_name_and_place(p)} eliminated.`)
- else
- // log(`Eliminated ${piece_name(p)}.`)
- log(`${piece_name(p)} eliminated.`)
+function eliminate_piece(p) {
+ push_summary(game.summary.eliminated, p)
unstack_force(p)
set_unit_reduced(p, 0)
game.location[p] = 0
@@ -1801,6 +1783,12 @@ function eliminate_piece(p, verbose=true) {
}
}
+function eliminate_leader(p) {
+ unstack_force(p)
+ set_unit_reduced(p, 0)
+ game.location[p] = 0
+}
+
function eliminate_indian_tribe(s) {
for (let p of indians.pieces_from_space[s])
if (is_piece_unbesieged(p))
@@ -1825,11 +1813,7 @@ function is_seven_command_leader(who) {
function place_piece(who, to) {
game.location[who] = to
- if (game.summary && game.summary.placed)
- push_summary(game.summary.placed, who)
- else
- // log(`Placed ${log_piece_name_and_place(who)}.`)
- log(`${log_piece_name_and_place(who)} placed.`)
+ push_summary(game.summary.placed, who)
// remember last placed 7-command leader(s)
if (is_seven_command_leader(who)) {
@@ -1885,34 +1869,34 @@ function recapture_british_fortress(s) {
}
function capture_enemy_fort_intact(s) {
- log(`Captured intact fort at %${s}.`)
+ log(`Captured intact fort.`)
set_delete(enemy_player.forts, s)
set_add(player.forts, s)
award_vp(2)
}
function capture_enemy_fort(s) {
- log(`Captured fort at %${s}.`)
+ log(`Captured fort.`)
set_delete(enemy_player.forts, s)
set_add(player.forts_uc, s)
award_vp(2)
}
function capture_enemy_stockade(s) {
- log(`Captured stockade at %${s}.`)
+ log(`Captured stockade.`)
set_delete(enemy_player.stockades, s)
set_add(player.stockades, s)
award_vp(1)
}
function destroy_enemy_stockade_after_battle(s) {
- log(`Destroyed stockade at %${s}.`)
+ log(`Destroyed stockade.`)
set_delete(enemy_player.stockades, s)
award_vp(1)
}
function destroy_enemy_stockade_in_raid(s) {
- log(`Destroyed stockade at %${s}.`)
+ log(`Destroyed stockade.`)
set_delete(enemy_player.stockades, s)
}
@@ -2277,24 +2261,41 @@ function gen_card_menu(card) {
}
function card_name(card) {
- return `#${card} ${cards[card].name} [${cards[card].activation}]`
+ return `(${cards[card].activation}) ${cards[card].name}`
}
-function play_card(card) {
- log(`${game.active} played\n${card_name(card)}.`)
+function play_card_for_event(card) {
+ log(`Played C${card} for event.`)
remove_from_array(player.hand, card)
game.last_card = card
- if (cards[card].special === 'remove')
+ if (cards[card].special === 'remove') {
+ log("Removed card.")
game.removed.push(card)
- else
+ } else {
+ game.discard.push(card)
+ }
+}
+
+function play_card_for_response(card) {
+ log(`${game.active} played C${card}.`)
+ remove_from_array(player.hand, card)
+ game.last_card = card
+ if (cards[card].special === 'remove') {
+ log("Removed card.")
+ game.removed.push(card)
+ } else {
game.discard.push(card)
+ }
+}
+
+function play_card_for_value(card, reason) {
+ log(`Played C${card} ${reason}.`)
+ remove_from_array(player.hand, card)
+ game.last_card = card
+ game.discard.push(card)
}
function discard_card(card, reason) {
- if (reason)
- log(`${game.active} discarded\n${card_name(card)}\n${reason}.`)
- else
- log(`${game.active} discarded\n${card_name(card)}.`)
remove_from_array(player.hand, card)
game.last_card = card
game.discard.push(card)
@@ -2318,7 +2319,8 @@ states.action_phase = {
push_undo()
player.did_construct = 0
logbr()
- play_card(card)
+ play_card_for_event(card)
+ logbr()
events[cards[card].event].play(card)
},
activate_force(card) {
@@ -2340,12 +2342,13 @@ states.action_phase = {
discard(card) {
logbr()
player.did_construct = 0
+ log(`Discarded C${card}.`)
discard_card(card)
end_action_phase()
},
pass() {
logbr()
- log(game.active + " passed.")
+ log("Passed.")
player.passed = 1
end_action_phase()
},
@@ -2356,7 +2359,7 @@ states.action_phase = {
function goto_activate_individually(card) {
push_undo()
player.did_construct = 0
- discard_card(card, "to activate units individually")
+ play_card_for_value(card, "to activate units individually")
game.state = 'activate_individually'
game.activation_value = 0
game.count = cards[card].activation
@@ -2366,7 +2369,7 @@ function goto_activate_individually(card) {
function goto_activate_force(card) {
push_undo()
player.did_construct = 0
- discard_card(card, "to activate a force")
+ play_card_for_value(card, "to activate a force")
game.state = 'activate_force'
game.activation_value = cards[card].activation
}
@@ -2389,14 +2392,14 @@ states.activate_individually = {
view.actions.end_activations = 1
if (game.count >= 1) {
for (let p = first_friendly_leader; p <= last_friendly_leader; ++p) {
- if (is_piece_on_map(p) && !game.activation.includes(p)) {
+ if (is_piece_on_map(p) && !set_has(game.activation, p)) {
gen_action_piece(p)
}
}
}
if (game.count > 0) {
for (let p = first_friendly_unit; p <= last_friendly_unit; ++p) {
- if (is_piece_on_map(p) && !game.activation.includes(p)) {
+ if (is_piece_on_map(p) && !set_has(game.activation, p)) {
if (game.count >= 0.5) {
if (is_indian(p))
gen_action_piece(p)
@@ -2416,7 +2419,7 @@ states.activate_individually = {
},
piece(p) {
push_undo()
- game.activation.push(p)
+ set_add(game.activation, p)
if (is_drilled_troops(p))
game.count = 0
else if (is_indian(p))
@@ -2474,7 +2477,7 @@ states.select_campaign_1 = {
view.prompt = "Campaign: Select the first leader."
for (let p = first_friendly_leader; p <= last_friendly_leader; ++p) {
if (is_piece_on_map(p))
- if (!game.activation.includes(p))
+ if (!set_has(game.activation, p))
if (can_activate_force(p))
gen_action_piece(p)
}
@@ -2495,7 +2498,7 @@ states.select_campaign_2 = {
view.prompt = "Campaign: Select the second leader."
for (let p = first_friendly_leader; p <= last_friendly_leader; ++p) {
if (is_piece_on_map(p) && !is_piece_in_force(p, game.activation[0]))
- if (!game.activation.includes(p))
+ if (!set_has(game.activation, p))
if (can_activate_force(p))
gen_action_piece(p)
}
@@ -2513,7 +2516,8 @@ states.select_campaign_2 = {
function goto_pick_first_move() {
if (game.activation.length > 1) {
logbr()
- log("Selected\n" + game.activation.map(log_piece_name_and_place).join(",\n") + ".")
+ let summary = map_group_by(game.activation, piece_space)
+ print_summary(summary, "Activated")
game.state = 'pick_move'
} else if (game.activation.length > 0) {
goto_move_piece(game.activation.pop())
@@ -2541,7 +2545,7 @@ states.pick_move = {
game.activation.forEach(gen_action_piece)
},
piece(p) {
- remove_from_array(game.activation, p)
+ set_delete(game.activation, p)
goto_move_piece(p)
},
}
@@ -2603,7 +2607,7 @@ states.designate_force = {
for_each_friendly_leader_in_node(where, p => {
if (game.force.reason === 'avoid' && is_piece_inside(p))
return // continue
- if (game.activation && game.activation.includes(p))
+ if (game.activation && set_has(game.activation, p))
return // continue
if (p !== commander && leader_command(p) <= leader_command(commander)) {
can_pick_up = true
@@ -2678,7 +2682,7 @@ states.designate_force = {
for_each_friendly_leader_in_node(where, p => {
if (game.force.reason === 'avoid' && is_piece_inside(p))
return // continue
- if (game.activation && game.activation.includes(p))
+ if (game.activation && set_has(game.activation, p))
return // continue
if (p !== commander && leader_command(p) <= leader_command(commander))
move_piece_to(p, box)
@@ -2730,11 +2734,11 @@ function end_designate_force() {
delete game.force
switch (reason) {
case 'campaign_1':
- game.activation.push(commander)
+ set_add(game.activation, commander)
game.state = 'select_campaign_2'
break
case 'campaign_2':
- game.activation.push(commander)
+ set_add(game.activation, commander)
goto_pick_first_move()
break
case 'move':
@@ -2809,22 +2813,32 @@ states.designate_force_lone_ax = {
// MOVE
-function describe_force(force, verbose) {
+function log_force_with(force) {
if (is_leader(force) && count_pieces_in_force(force) > 1) {
- let desc = verbose ? log_piece_name_and_place(force) : piece_name(force)
+ let list = []
for_each_piece_in_force(force, p => {
if (p !== force)
- desc += ",\n" + piece_name(p)
+ list.push(p)
})
- return desc
+ log(">with\n" + make_summary(list))
+ }
+}
+
+function log_force(force) {
+ if (is_leader(force) && count_pieces_in_force(force) > 1) {
+ let list = []
+ for_each_piece_in_force(force, p => {
+ if (p !== force)
+ list.push(p)
+ })
+ log(">with P" + force + "\n" + make_summary(list))
} else {
- return verbose ? log_piece_name_and_place(force) : piece_name(force)
+ log(">with P" + force)
}
}
function goto_move_piece(who) {
logbr()
- log(`Activated\n${describe_force(who, true)}.`)
let from = piece_space(who)
game.state = 'move'
@@ -2849,16 +2863,13 @@ function goto_move_piece(who) {
from: {},
aux: list_auxiliary_units_in_force(who)
}
- start_move()
-}
-function start_move() {
if (has_besieged_enemy_fortifications(moving_piece_space())) {
game.state = 'siege_or_move'
} else if (is_piece_inside(moving_piece())) {
goto_break_siege()
} else {
- resume_move()
+ start_move()
}
}
@@ -2889,25 +2900,35 @@ states.siege_or_move = {
},
siege() {
push_undo()
+ log(`Activated P${game.move.moving}`)
+ log(`>at %${game.move.where}`)
+ log_force_with(game.move.moving)
goto_siege(moving_piece_space())
},
assault() {
push_undo()
+ log(`Activated P${game.move.moving}`)
+ log(`>at %${game.move.where}`)
+ log_force_with(game.move.moving)
goto_assault(moving_piece_space())
},
play_event(c) {
push_undo()
game.siege_where = moving_piece_space()
- play_card(c)
+ play_card_for_response(c)
goto_surrender()
},
move() {
push_undo()
- resume_move()
+ start_move()
},
}
function goto_break_siege() {
+ log(`Moved P${game.move.moving}`)
+ log(`>from %${game.move.where}`)
+ log_force_with(game.move.moving)
+
let here = moving_piece_space()
game.move.came_from = here
goto_avoid_battle()
@@ -2952,6 +2973,13 @@ function max_movement_cost(type) {
}
}
+function start_move() {
+ log(`Moved P${game.move.moving}`)
+ log(`>from %${game.move.where}`)
+ log_force_with(game.move.moving)
+ resume_move()
+}
+
function resume_move() {
let who = moving_piece()
let where = moving_piece_space()
@@ -3304,9 +3332,9 @@ function apply_move(to) {
}
if (game.move.infiltrated)
- log(`Infiltrated %${to}.`)
+ log(`>to %${to} *`)
else
- log(`Moved to %${to}.`)
+ log(`>to %${to}`)
move_piece_to(who, to)
lift_sieges_and_amphib()
@@ -3413,7 +3441,7 @@ states.move = {
},
play_event(card) {
push_undo()
- play_card(card)
+ play_card_for_response(card)
if (card === GEORGE_CROGHAN) {
game.events.george_croghan = 1
resume_move()
@@ -3445,8 +3473,7 @@ states.move = {
},
drop_off() {
push_undo()
- if (game.summary)
- game.summary.drop_off = []
+ game.summary.drop_off = []
game.state = 'drop_off'
},
siege() {
@@ -3508,15 +3535,12 @@ states.drop_off = {
},
piece(who) {
push_undo()
- if (game.summary)
- game.summary.drop_off.push(who)
- else
- log(`Dropped off ${piece_name(who)}.`)
+ set_add(game.summary.drop_off, who)
move_piece_to(who, moving_piece_space())
},
next() {
push_undo()
- print_plain_summary("Dropped off", 'drop_off')
+ print_plain_summary(">>dropped", 'drop_off')
resume_move()
},
}
@@ -3543,10 +3567,10 @@ states.foul_weather = {
view.who = p
view.where = moving_piece_space()
if (player.hand.includes(FOUL_WEATHER)) {
- view.prompt = `${piece_name_and_place(p)} is about to move. You may play "Foul Weather".`
+ view.prompt = `${piece_name_and_place(p)} to move. You may play "Foul Weather".`
gen_action('play_event', FOUL_WEATHER)
} else {
- view.prompt = `${piece_name_and_place(p)} is about to move. You don't have "Foul Weather".`
+ view.prompt = `${piece_name_and_place(p)} to move. You don't have "Foul Weather".`
}
view.actions.pass_fw_season = 1
if (game.activation && game.activation.length > 0)
@@ -3558,7 +3582,7 @@ states.foul_weather = {
// console.log("RETRO STAY")
delete game.retro_foul_weather
}
- play_card(c)
+ play_card_for_response(c)
game.events.foul_weather = 1
game.move.used = 0
set_active_enemy()
@@ -3604,15 +3628,15 @@ states.lake_schooner = {
view.who = who
view.where = to
if (player.hand.includes(LAKE_SCHOONER)) {
- view.prompt = `${piece_name(who)} is about to move from ${space_name(from)} to ${space_name(to)}. You may play "Lake Schooner".`
+ view.prompt = `${piece_name(who)} to move from ${space_name(from)} to ${space_name(to)}. You may play "Lake Schooner".`
gen_action('play_event', LAKE_SCHOONER)
} else {
- view.prompt = `${piece_name(who)} is about to move from ${space_name(from)} to ${space_name(to)}. You don't have "Lake Schooner".`
+ view.prompt = `${piece_name(who)} to move from ${space_name(from)} to ${space_name(to)}. You don't have "Lake Schooner".`
}
view.actions.pass = 1
},
play_event(c) {
- play_card(c)
+ play_card_for_response(c)
let who = moving_piece()
let from = moving_piece_space()
let to = game.move.lake_schooner
@@ -3620,7 +3644,7 @@ states.lake_schooner = {
set_active_enemy()
- log(`${piece_name(who)} stopped at %${from}.`)
+ log(`Stopped at %${from}.`)
if (would_be_infiltration_move(who, from, to)) {
// 6.63 eliminate if forced back into enemy-occupied space during infiltration
@@ -3650,7 +3674,7 @@ states.amphibious_landing = {
prompt() {
let who = moving_piece()
let from = moving_piece_space()
- view.prompt = `Amphibious Landing: Select a destination for ${piece_name_and_place(who)}.`
+ view.prompt = `Amphibious Landing: Select a destination for ${piece_name(who)}.`
view.who = who
if (from === HALIFAX) {
gen_action_move(from, LOUISBOURG)
@@ -3675,7 +3699,7 @@ function remove_siege_marker(where) {
}
function place_siege_marker(where) {
- log(`Started siege at %${where}.`)
+ log(`Placed siege marker.`)
game.sieges[where] = 0
}
@@ -3963,14 +3987,25 @@ function attempt_intercept() {
}
game.move.did_attempt_intercept = 1
- let die = roll_die("to intercept with\n" + describe_force(who, true))
- if (is_leader(who))
- die = modify(die, leader_tactics(who), "leader tactics")
- if (die >= 4) {
- log("Intercepted!")
+ logbr()
+ log("Intercept")
+ log(">from %" + piece_space(who))
+ log_force(who)
+
+ let die = roll_die()
+ let drm = 0
+ let drm_text = ""
+ if (is_leader(who)) {
+ drm = leader_tactics(who)
+ drm_text = " + " + leader_tactics_text(who)
+ }
+
+ if (die + drm >= 4) {
+ log(`>D${die}${drm_text} vs 4 \u2013 success`)
end_intercept_success()
} else {
- log("Failed.")
+ log(`>D${die}${drm_text} vs 4 \u2013 failed`)
+ logbr()
end_intercept_fail()
}
}
@@ -4006,8 +4041,7 @@ function goto_designate_inside() {
if (has_enemy_fortress(where) || has_enemy_fort(where)) {
set_active_enemy()
game.state = 'designate_inside'
- if (game.summary)
- game.summary.inside = []
+ game.summary.inside = []
return goto_retroactive_foul_weather()
}
}
@@ -4031,21 +4065,13 @@ states.designate_inside = {
},
piece(p) {
push_undo()
- if (game.summary) {
- game.summary.inside.push(p)
- } else {
- if (is_fortress(moving_piece_space()))
- log(`${piece_name(p)} withdrew into fortress.`)
- else
- log(`${piece_name(p)} withdrew into fort.`)
- }
+ set_add(game.summary.inside, p)
set_piece_inside(p)
},
end_withdraw() {
- if (is_fortress(moving_piece_space()))
- print_plain_summary("Withdrew into fortress", 'inside')
- else
- print_plain_summary("Withdrew into fort", 'inside')
+ logbr()
+ print_plain_summary("Withdrew", 'inside')
+ logbr()
set_active_enemy()
goto_avoid_battle()
},
@@ -4113,24 +4139,37 @@ states.avoid_who = {
}
function attempt_avoid_battle() {
- let avoiding = avoiding_piece()
+ let who = avoiding_piece()
let moving = moving_piece()
let from = moving_piece_space()
+ logbr()
+
// 6.8 Exception: Auxiliary and all-Auxiliary forces automatically succeed.
- if (is_wilderness_or_mountain(from) && force_has_only_auxiliary_units(avoiding) && !force_has_auxiliary(moving)) {
- log("Auxiliaries avoided battle\n" + describe_force(avoiding, false) + ".")
+ if (is_wilderness_or_mountain(from) && force_has_only_auxiliary_units(who) && !force_has_auxiliary(moving)) {
+ log("Avoid battle by auxiliaries")
+ log_force(who)
game.state = 'avoid_to'
return
}
- let die = roll_die("to avoid battle\n" + describe_force(avoiding, false))
- if (is_leader(avoiding))
- die = modify(die, leader_tactics(avoiding), "leader tactics")
- if (die >= 4) {
- game.state = 'avoid_to'
+ log("Avoid battle")
+ log_force(who)
+
+ let die = roll_die()
+ let drm = 0
+ let drm_text = ""
+ if (is_leader(who)) {
+ drm = leader_tactics(who)
+ drm_text = " + " + leader_tactics_text(who)
+ }
+
+ if (die + drm >= 4) {
+ log(`>D${die}${drm_text} vs 4`)
+ game.state = "avoid_to"
} else {
- log("Failed.")
+ log(`>D${die}${drm_text} vs 4 \u2013 failed`)
+ logbr()
end_avoid_battle()
}
}
@@ -4179,17 +4218,14 @@ states.avoid_to = {
}
},
space(to) {
- log(`Avoided to %${to}.`)
- end_avoid_battle_success(to)
+ let who = avoiding_piece()
+ move_piece_to(who, to)
+ log(`>>to %${to}`)
+ logbr()
+ end_avoid_battle()
},
}
-function end_avoid_battle_success(to) {
- let who = avoiding_piece()
- move_piece_to(who, to)
- end_avoid_battle()
-}
-
function end_avoid_battle() {
let who = avoiding_piece()
if (who)
@@ -4291,16 +4327,16 @@ function combat_result(die, str, shift) {
let k = clamp(i + shift, 0, COMBAT_RESULT_TABLE.length-1)
let r = COMBAT_RESULT_TABLE[k][1][die]
if (k === 0)
- log(`Lookup ${die} on column 0.`)
+ log(`Combat ${die} \xd7 0: ${r}`)
else if (k === COMBAT_RESULT_TABLE.length - 1)
- log(`Lookup ${die} on column >= 28.`)
+ log(`Combat ${die} \xd7 28+: ${r}`)
else {
let a = COMBAT_RESULT_TABLE[k-1][0] + 1
let b = COMBAT_RESULT_TABLE[k][0]
if (a === b)
- log(`Lookup ${die} on column ${b}.`)
+ log(`Combat ${die} \xd7 ${b}: ${r}`)
else
- log(`Lookup ${die} on column ${a}-${b}.`)
+ log(`Combat ${die} \xd7 ${a}-${b}: ${r}`)
}
return r
}
@@ -4353,13 +4389,18 @@ function goto_battle(where, is_assault) {
// 5.36 unit or leader may not be activated if it participated in combat or assault.
if (game.activation) {
+ let list = []
for_each_attacking_piece(p => {
- if (game.activation.includes(p)) {
- log(`Deactivated ${log_piece_name_and_place(p)}.`)
- remove_from_array(game.activation, p)
+ if (set_has(game.activation, p)) {
+ list.push(p)
+ set_delete(game.activation, p)
unstack_force(p)
}
})
+ if (list.length > 0) {
+ list = map_group_by(list, piece_space)
+ print_summary(list, "Deactivated")
+ }
}
if (game.raid)
@@ -4425,8 +4466,7 @@ function goto_battle_militia() {
if (has_enemy_raided_marker(s))
return goto_battle_sortie()
game.state = 'militia_in_battle'
- if (game.summary)
- game.summary.deploy = []
+ game.summary.deploy = []
} else {
goto_battle_sortie()
}
@@ -4454,10 +4494,7 @@ states.militia_in_battle = {
move_piece_to(p, game.battle.where)
if (game.active === game.battle.attacker)
game.battle.atk_pcs.push(p)
- if (game.summary)
- game.summary.deploy.push(p)
- else
- log(`Deployed ${piece_name(p)}.`)
+ set_add(game.summary.deploy, p)
},
end_militia() {
print_plain_summary("Deployed", 'deploy')
@@ -4469,25 +4506,21 @@ function goto_battle_sortie() {
set_active(game.battle.attacker)
if (has_besieged_friendly_units(game.battle.where)) {
game.state = 'sortie'
- if (game.summary)
- game.summary.sortie = []
+ game.summary.sortie = []
} else {
goto_battle_attacker_events()
}
}
function sortie_with_piece(p) {
- if (game.summary)
- game.summary.sortie.push(p)
- else
- log(`${piece_name(p)} sortied.`)
+ set_add(game.summary.sortie, p)
game.battle.atk_pcs.push(p)
// 5.36 unit or leader may not be activated if it participated in combat or assault.
unstack_piece_from_force(p)
if (game.activation)
- remove_from_array(game.activation, p)
+ set_delete(game.activation, p)
}
states.sortie = {
@@ -4703,7 +4736,7 @@ states.attacker_events = {
},
play_event(c) {
push_undo()
- play_card(c)
+ play_card_for_response(c)
switch (c) {
case AMBUSH_1:
case AMBUSH_2:
@@ -4714,6 +4747,7 @@ states.attacker_events = {
break
case FIELDWORKS_1:
case FIELDWORKS_2:
+ log("Removed fieldworks.")
remove_fieldworks(game.battle.where)
break
}
@@ -4778,7 +4812,7 @@ states.defender_events = {
},
play_event(c) {
push_undo()
- play_card(c)
+ play_card_for_response(c)
switch (c) {
case AMBUSH_1:
case AMBUSH_2:
@@ -4792,6 +4826,7 @@ states.defender_events = {
break
case FIELDWORKS_1:
case FIELDWORKS_2:
+ log("Placed fieldworks.")
place_fieldworks(game.battle.where)
break
}
@@ -4842,7 +4877,7 @@ function end_def_fire() {
}
function end_step_losses() {
- flush_summary()
+ flush_losses_summary()
if (game.active === game.battle.attacker)
goto_atk_leader_check()
else
@@ -4850,7 +4885,7 @@ function end_step_losses() {
}
function end_leader_check() {
- flush_summary()
+ flush_losses_summary()
delete game.battle.leader_check
if (game.events.ambush === game.battle.attacker) {
if (game.active === game.battle.defender)
@@ -4887,27 +4922,21 @@ function goto_atk_fire() {
logbr()
log(".b Attacker")
- let str = attacker_combat_strength()
let shift = 0
- if (game.events.ambush === game.battle.attacker) {
- log(`Strength ${str} \xd7 2 for ambush.`)
- str *= 2
- } else {
- log(`Strength ${str}.`)
- }
let die = game.battle.atk_die = roll_die()
if (is_leader(game.battle.atk_commander)) {
- die = modify(die, leader_tactics(game.battle.atk_commander), "leader tactics")
+ log(">D" + die + " + " + leader_tactics_text(game.battle.atk_commander))
+ die += leader_tactics(game.battle.atk_commander)
+ } else {
+ log(">D" + die)
}
+
if (game.events.coehorns === game.battle.attacker) {
die = modify(die, 2, "for coehorns")
}
- if (game.battle.assault) {
- log(`1 column left for assaulting`)
- shift -= 1
- } else {
+ if (!game.battle.assault) {
if (is_wilderness_or_mountain(game.battle.where)) {
let atk_has_ax = some_attacking_piece(p => is_auxiliary(p) || is_light_infantry(p))
let def_has_ax = some_defending_piece(p => is_auxiliary(p) || is_light_infantry(p))
@@ -4926,15 +4955,28 @@ function goto_atk_fire() {
if (has_enemy_stockade(game.battle.where)) {
die = modify(die, -1, "vs stockade")
}
+ }
+
+ let str = attacker_combat_strength()
+ if (game.events.ambush === game.battle.attacker) {
+ log(`Strength ${str} \xd7 2 for ambush`)
+ str *= 2
+ } else {
+ log(`Strength ${str}`)
+ }
+
+ if (game.battle.assault) {
+ log(`>1L for assaulting`)
+ shift -= 1
+ } else {
if (has_fieldworks(game.battle.where)) {
// NOTE: Ignore fieldworks during assault, as they belong to the besieging forces.
- log(`1 column left vs fieldworks`)
+ log(`>1L vs fieldworks`)
shift -= 1
}
}
game.battle.atk_result = combat_result(die, str, shift)
- log(`Attacker result: ${game.battle.atk_result}.`)
end_atk_fire()
}
@@ -4954,20 +4996,15 @@ function goto_def_fire() {
logbr()
log(".b Defender")
- let str = defender_combat_strength()
- let shift = 0
- if (game.events.ambush === game.battle.defender) {
- log(`Strength ${str} \xd7 2 for ambush.`)
- str *= 2
- } else {
- log(`Strength ${str}.`)
- }
-
let die = game.battle.def_die = roll_die()
let p = find_friendly_commanding_leader_in_space(game.battle.where)
if (p) {
- die = modify(die, leader_tactics(p), "leader tactics")
+ log(">D" + die + " + " + leader_tactics_text(p))
+ die += leader_tactics(p)
+ } else {
+ log(">D" + die)
}
+
if (game.events.coehorns === game.battle.defender) {
die = modify(die, 2, "for coehorns")
}
@@ -4987,8 +5024,15 @@ function goto_def_fire() {
}
}
- game.battle.def_result = combat_result(die, str, shift)
- log(`Defender result: ${game.battle.def_result}.`)
+ let str = defender_combat_strength()
+ if (game.events.ambush === game.battle.defender) {
+ log(`Strength ${str} \xd7 2 for ambush`)
+ str *= 2
+ } else {
+ log(`Strength ${str}`)
+ }
+
+ game.battle.def_result = combat_result(die, str, 0)
end_def_fire()
}
@@ -5101,7 +5145,7 @@ states.step_losses = {
--game.battle.step_loss
if (game.battle.dt_loss > 0 && is_drilled_troops(p))
--game.battle.dt_loss
- if (reduce_unit(p, false)) {
+ if (reduce_unit(p)) {
remove_from_array(game.battle.atk_pcs, p)
remove_from_array(game.battle.units, p)
}
@@ -5154,11 +5198,11 @@ states.raid_step_losses = {
piece(p) {
push_undo()
--game.raid.step_loss
- if (reduce_unit(p, false))
+ if (reduce_unit(p))
remove_from_array(game.raid.units, p)
},
end_losses() {
- flush_summary()
+ flush_losses_summary()
goto_raid_leader_check()
},
}
@@ -5175,6 +5219,7 @@ function goto_atk_leader_check() {
})
}
if (game.battle.leader_check.length > 0) {
+ log("Leaders")
game.state = 'leader_check'
} else {
end_leader_check()
@@ -5191,7 +5236,7 @@ function goto_def_leader_check() {
})
}
if (game.battle.leader_check.length > 0) {
- log(`Leader loss check.`)
+ log("Leaders")
game.state = 'leader_check'
} else {
end_leader_check()
@@ -5206,11 +5251,14 @@ states.leader_check = {
gen_action_piece(game.battle.leader_check[i])
},
piece(p) {
- let die = roll_die("for " + piece_name(p))
+ let die = roll_die()
if (die === 1) {
+ log(">D" + die + " P" + p + " \u2013 eliminated")
if (game.battle)
remove_from_array(game.battle.atk_pcs, p)
- eliminate_piece(p, false)
+ eliminate_leader(p)
+ } else {
+ log(">D" + die + " P" + p)
}
remove_from_array(game.battle.leader_check, p)
if (game.battle.leader_check.length === 0)
@@ -5225,7 +5273,7 @@ function goto_raid_leader_check() {
game.raid.leader_check.push(p)
})
if (game.raid.leader_check.length > 0) {
- log(`Leader loss check.`)
+ log("Leader")
game.state = 'raid_leader_check'
} else {
delete game.raid.leader_check
@@ -5244,13 +5292,16 @@ states.raid_leader_check = {
gen_action_piece(game.raid.leader_check[i])
},
piece(p) {
- let die = roll_die("for " + piece_name(p))
- if (die === 1)
- eliminate_piece(p, false)
+ let die = roll_die()
+ log(">D" + die + " P" + p)
+ if (die === 1) {
+ log(">>eliminated")
+ eliminate_leader(p)
+ }
remove_from_array(game.raid.leader_check, p)
if (game.raid.leader_check.length === 0) {
delete game.raid.leader_check
- flush_summary()
+ flush_losses_summary()
goto_raiders_go_home()
}
},
@@ -5261,16 +5312,12 @@ states.raid_leader_check = {
function return_militia(where) {
let box = department_militia(where)
if (box) {
- let n = 0
- for (let p = 1; p <= last_piece; ++p) {
- if (is_militia(p) && is_piece_in_space(p, where)) {
+ for (let p = first_british_militia; p <= last_british_militia; ++p)
+ if (is_piece_in_space(p, where))
+ move_piece_to(p, box)
+ for (let p = first_french_militia; p <= last_french_militia; ++p)
+ if (is_piece_in_space(p, where))
move_piece_to(p, box)
- ++n
- }
- }
- if (n > 0) {
- log(`${n} Militia units returned to their box.`)
- }
}
}
@@ -5333,10 +5380,14 @@ function determine_winner_battle() {
award_british_vp(1)
}
- return_militia(game.battle.where)
+ return_militia(where)
- if (victor === game.battle.attacker)
- remove_fieldworks(where)
+ if (victor === game.battle.attacker) {
+ if (has_fieldworks(where)) {
+ log("Removed fieldworks.")
+ remove_fieldworks(where)
+ }
+ }
logbr()
@@ -5396,7 +5447,7 @@ function determine_winner_battle() {
function eliminate_enemy_pieces_inside(where) {
for (let p = first_enemy_piece; p <= last_enemy_piece; ++p)
if (is_piece_besieged_in_space(p, where))
- eliminate_piece(p, false)
+ eliminate_piece(p)
}
function determine_winner_assault() {
@@ -5413,6 +5464,7 @@ function determine_winner_assault() {
if (victor === game.battle.attacker) {
log(".b Attacker Won Assault")
eliminate_enemy_pieces_inside(where)
+ flush_losses_summary()
remove_siege_marker(where)
if (has_enemy_fortress(where)) {
capture_enemy_fortress(where)
@@ -5474,15 +5526,15 @@ states.retreat_attacker = {
let to = game.retreat.to
// NOTE: Besieged pieces that sortie out are 'inside' so not affected by the code below.
- init_retreat_summary()
log(".b Attacker Retreat")
+ game.summary.retreat = []
for_each_friendly_piece_in_space(from, p => {
if (is_piece_unbesieged(p)) {
if (can_attacker_retreat_from_to(p, from, to)) {
push_retreat_summary(p, "to %" + to)
move_piece_to(p, to)
} else {
- eliminate_piece(p, false)
+ eliminate_piece(p)
}
} else {
if (is_fortress(to))
@@ -5492,7 +5544,7 @@ states.retreat_attacker = {
}
})
flush_retreat_summary()
- flush_summary()
+ flush_losses_summary()
logbr()
end_retreat_attacker(to)
}
@@ -5520,7 +5572,7 @@ function end_retreat_attacker(to) {
function goto_retreat_defender() {
set_active(game.battle.defender)
game.state = 'retreat_defender'
- init_retreat_summary()
+ game.summary.retreat = []
}
function can_defender_retreat_from_to(p, from, to) {
@@ -5627,10 +5679,10 @@ states.retreat_defender = {
let from = game.battle.where
for_each_friendly_piece_in_space(from, p => {
if (is_piece_unbesieged(p))
- eliminate_piece(p, false)
+ eliminate_piece(p)
})
flush_retreat_summary()
- flush_summary()
+ flush_losses_summary()
logbr()
end_retreat()
},
@@ -5787,12 +5839,12 @@ states.retreat_lone_leader = {
let who = pick_unbesieged_leader(from)
if (from === to) {
if (is_fortress(to))
- log(`${piece_name(who)} retreated into fortress.`)
+ log(`P${who} retreated into fortress.`)
else
- log(`${piece_name(who)} retreated into fort.`)
+ log(`P${who} retreated into fort.`)
set_piece_inside(who)
} else {
- log(`${piece_name(who)} retreated to %${to}.`)
+ log(`P${who} retreated to %${to}.`)
move_piece_to(who, to)
}
resume_retreat_lone_leader(from)
@@ -5883,7 +5935,7 @@ states.siege_coehorns_attacker = {
view.actions.pass = 1
},
play_event(c) {
- play_card(c)
+ play_card_for_response(c)
game.events.coehorns = game.active
end_siege_coehorns_attacker()
},
@@ -5912,7 +5964,7 @@ states.siege_coehorns_defender = {
view.actions.pass = 1
},
play_event(c) {
- play_card(c)
+ play_card_for_response(c)
game.events.coehorns = game.active
end_siege_coehorns_defender()
},
@@ -5945,7 +5997,7 @@ states.siege_surrender = {
view.actions.pass = 1
},
play_event(c) {
- play_card(c)
+ play_card_for_response(c)
goto_surrender()
},
pass() {
@@ -5985,7 +6037,7 @@ function goto_surrender_place() {
}
states.surrender = {
- inactive: "to play Surrender",
+ inactive: "to execute event",
prompt() {
view.prompt = "Surrender! Place defenders at the closest unbesieged fortification."
view.where = game.siege_where
@@ -6016,32 +6068,45 @@ function end_surrender() {
}
const SIEGE_TABLE_RESULT = {
- 0: "No effect.",
- 1: "Siege +1.",
- 2: "Siege +2."
+ 0: "NE",
+ 1: "+1",
+ 2: "+2"
}
function resolve_siege() {
let where = game.siege_where
+ delete game.siege_where
logbr()
log(".siege %" + where)
logbr()
let att_leader = find_friendly_commanding_leader_in_space(where)
let def_leader = find_enemy_commanding_leader_in_space(where)
- let die = roll_die("for siege")
- die = modify(die, leader_tactics(att_leader), "besieging leader")
+
+ let die = roll_die()
+
+ log(".b Siege")
+ if (def_leader) {
+ log(`>D${die} + ${leader_tactics_text(att_leader)} \u2212 ${leader_tactics_text(def_leader)}`)
+ die += leader_tactics(att_leader)
+ die -= leader_tactics(def_leader)
+ } else {
+ log(`>D${die} + ${leader_tactics_text(att_leader)}`)
+ die += leader_tactics(att_leader)
+ }
+
if (game.events.coehorns)
die = modify(die, game.events.coehorns === game.active ? 2 : -2, "for coehorns")
- if (def_leader)
- die = modify(die, -leader_tactics(def_leader), "defending leader")
+
if (where === LOUISBOURG)
die = modify(die, -1, "for Louisbourg")
- let result = SIEGE_TABLE[clamp(die, 0, 7)]
- log(`Lookup ${die} on siege table.`)
- log(SIEGE_TABLE_RESULT[result])
+
+ die = clamp(die, 0, 7)
+ let result = SIEGE_TABLE[die]
+
+ log(`Siege ${die}: ${SIEGE_TABLE_RESULT[result]}`)
if (result > 0) {
let level = change_siege_marker(where, result)
- log("Siege level " + level + ".")
+ log(">to level " + level)
}
goto_assault_possible(where)
}
@@ -6163,7 +6228,7 @@ states.militia_against_raid = {
piece(p) {
push_undo()
move_piece_to(p, game.raid.where)
- log(`Deployed ${piece_name(p)}.`)
+ log(`Deployed militia.`)
game.count --
},
end_militia() {
@@ -6180,6 +6245,11 @@ const RAID_TABLE = {
cultivated: [ 2, 0, 0, 0, 1, 1, 0, 0 ],
}
+const RAID_TABLE_TEXT = {
+ stockade: [ "2", "1", "1", "NE", "2", "Success, 1", "Success", "Success" ],
+ cultivated: [ "2", "NE", "NE", "NE", "1", "Success, 1", "Success", "Success" ],
+}
+
function goto_raid_events() {
if (is_enemy_card_available(BLOCKHOUSES) && !enemy_player.pass_bh) {
set_active_enemy()
@@ -6202,7 +6272,7 @@ states.raid_blockhouses = {
view.actions.pass = 1
},
play_event(c) {
- play_card(c)
+ play_card_for_response(c)
game.events.blockhouses = game.active
set_active_enemy()
resolve_raid()
@@ -6222,12 +6292,17 @@ function resolve_raid() {
let x_stockade = has_enemy_stockade(where)
let x_allied = has_enemy_allied_settlement(where)
- let natural_die = roll_die("for raid")
+ let natural_die = roll_die()
let die = natural_die
let commander = find_friendly_commanding_leader_in_space(where)
- if (commander)
- die = modify(die, leader_tactics(commander), "leader")
+ if (commander) {
+ log("Raid D" + natural_die + " + " + leader_tactics_text(commander))
+ die += leader_tactics(commander)
+ } else {
+ log("Raid D" + natural_die)
+ }
+
if (has_friendly_rangers(where))
die = modify(die, 1, "for rangers")
if (enemy_department_has_at_least_n_militia(where, 2))
@@ -6238,32 +6313,27 @@ function resolve_raid() {
column = 'stockade'
if (game.events.blockhouses === enemy()) {
column = 'stockade'
- log("vs enemy blockhouses")
+ log(">vs enemy blockhouses")
}
let result = clamp(die, 0, 7)
let success = result >= 5
let losses = RAID_TABLE[column][result]
+ let effect = RAID_TABLE_TEXT[column][result]
+
+ if (column === 'stockade')
+ log(`vs Stockade ${die}: ${effect}`)
+ else
+ log(`vs Cultivated ${die}: ${effect}`)
+ logbr()
- log(`Lookup ${die} vs ${column}.`)
if (success) {
- if (losses === 0)
- log(`Success.`)
- else
- log(`Success with one step loss.`)
if (x_stockade || x_allied || !has_friendly_raided_marker(where))
place_friendly_raided_marker(where)
if (x_stockade)
destroy_enemy_stockade_in_raid(where)
if (x_allied)
eliminate_indian_tribe(where)
- } else {
- if (losses === 0)
- log(`No effect.`)
- else if (losses === 1)
- log(`Failure with one step loss.`)
- else
- log(`Failure with two step losses.`)
}
game.raid.step_loss = losses
@@ -6307,7 +6377,7 @@ function goto_raiders_go_home() {
to: 0,
follow: {},
}
- init_go_home_summary()
+ game.summary.go_home = []
} else {
end_raiders_go_home()
}
@@ -6333,10 +6403,11 @@ function resume_indians_and_leaders_go_home() {
to: 0,
follow: {},
}
- init_go_home_summary()
+ game.summary.go_home = []
}
function end_indians_and_leaders_go_home() {
+ logbr()
flush_go_home_summary()
logbr()
if (game.active === FRANCE) {
@@ -6485,8 +6556,10 @@ states.go_home_to = {
space(to) {
let who = game.go_home.who
let from = game.go_home.from
- push_go_home_summary(who, to)
+
move_piece_to(who, to)
+ push_summary(game.summary.go_home, who)
+
if (is_indian(who)) {
let home = indians.space_from_piece[who]
game.count = 0
@@ -6562,8 +6635,9 @@ states.go_home_with_indians = {
let from = game.go_home.from
let to = game.go_home.to
- push_go_home_summary(p, to)
move_piece_to(p, to)
+ push_summary(game.summary.go_home, p)
+
if (game.count > 0 && is_leader(p))
game.count = 0
@@ -6704,7 +6778,7 @@ states.winter_attrition = {
push_undo()
if (is_unit_reduced_for_winter(p))
stack.n--
- reduce_unit(p, true)
+ reduce_unit(p)
remove_from_array(stack.dt, p)
},
end_attrition() {
@@ -6913,6 +6987,7 @@ states.demolish_fieldworks = {
gen_action_space(s)
},
space(s) {
+ log(`Demolished fieldworks at %${s}.`)
remove_fieldworks(s)
end_demolish()
}
@@ -6928,7 +7003,7 @@ function format_remain(n) {
function goto_construct_stockades(card) {
push_undo()
- discard_card(card, "to construct stockades")
+ play_card_for_value(card, "to construct")
player.did_construct = 1
game.state = 'construct_stockades'
game.count = cards[card].activation
@@ -6978,7 +7053,7 @@ states.construct_stockades = {
function goto_construct_forts(card) {
push_undo()
- discard_card(card, "to construct forts")
+ play_card_for_value(card, "to construct")
player.did_construct = 1
game.state = 'construct_forts'
game.count = cards[card].activation
@@ -7124,7 +7199,7 @@ states.massacre_1 = {
view.actions.pass = 1
},
play_event(c) {
- play_card(c)
+ play_card_for_response(c)
award_vp(1)
game.state = 'massacre_2'
set_active_enemy()
@@ -7154,7 +7229,7 @@ states.massacre_2 = {
}
},
piece(p) {
- eliminate_piece(p, false)
+ eliminate_piece(p)
},
end_event() {
set_active_enemy()
@@ -7308,10 +7383,13 @@ states.indian_alliance_roll = {
},
roll() {
let roll = roll_die()
- if (game.vp > 4)
+ if (game.vp > 4) {
game.count = roll
- else
+ log(`Full D${roll} indians.`)
+ } else {
game.count = Math.ceil(roll / 2)
+ log(`Half D${roll} indians.`)
+ }
game.state = 'indian_alliance'
},
}
@@ -7324,6 +7402,7 @@ states.indian_alliance_roll_gray = {
roll() {
let roll = roll_die()
game.count = roll
+ log(`Roll D${roll} indians.`)
game.state = 'indian_alliance'
},
}
@@ -7691,11 +7770,12 @@ states.louisbourg_squadrons = {
},
roll() {
let roll = roll_die()
+ log("Roll D" + roll + " vs 1-3.")
log("No amphibious landings this year.")
if (roll <= 3) {
log("No French naval moves ever.")
log("British may play Quiberon.")
- log("Card removed.")
+ log("Removed card.")
game.events.no_fr_naval = 1
remove_card(LOUISBOURG_SQUADRONS)
}
@@ -7749,8 +7829,8 @@ states.governor_vaudreuil_interferes = {
let p_loc = piece_space(p)
move_piece_to(a, p_loc)
move_piece_to(p, a_loc)
- log(`${piece_name(a)} moved to %${p_loc}.`)
- log(`${piece_name(p)} moved to %${a_loc}.`)
+ log(`P${a} moved to %${p_loc}.`)
+ log(`P${p} moved to %${a_loc}.`)
game.count = 0
} else {
push_undo()
@@ -7791,16 +7871,18 @@ states.small_pox = {
states.small_pox_roll = {
prompt() {
view.prompt = "Small Pox: Roll a die."
+ view.where = game.small_pox
view.actions.roll = 1
},
roll() {
let roll = roll_die()
if (count_units_in_space(game.small_pox) > 8) {
+ log("Full D" + roll + " steps.")
game.count = roll
} else {
+ log("Half D" + roll + " steps.")
game.count = Math.ceil(roll / 2)
}
- log(`Must eliminate ${game.count} steps.`)
game.state = 'small_pox_eliminate_steps'
set_active_enemy()
},
@@ -7808,6 +7890,7 @@ states.small_pox_roll = {
states.small_pox_eliminate_steps = {
prompt() {
+ view.where = game.small_pox
let done = true
if (game.count > 0) {
for_each_friendly_unit_in_space(game.small_pox, p => {
@@ -7832,10 +7915,11 @@ states.small_pox_eliminate_steps = {
},
piece(p) {
push_undo()
+ reduce_unit(p)
game.count --
- reduce_unit(p, false)
},
next() {
+ flush_losses_summary()
if (has_any_indians(game.small_pox)) {
game.state = 'small_pox_remove_indians'
} else {
@@ -7847,19 +7931,21 @@ states.small_pox_eliminate_steps = {
states.small_pox_remove_indians = {
prompt() {
view.prompt = `Small Pox at ${space_name(game.small_pox)}: Remove all indians.`
+ view.where = game.small_pox
for_each_unit_in_space(game.small_pox, p => {
if (is_indian(p))
gen_action_piece(p)
})
},
piece(p) {
- eliminate_piece(p, false)
+ eliminate_piece(p)
if (!has_any_indians(game.small_pox))
end_small_pox()
},
}
function end_small_pox() {
+ flush_losses_summary()
delete game.small_pox
set_active_enemy()
end_action_phase()
@@ -7881,12 +7967,13 @@ states.courier_intercepted_roll = {
},
roll() {
let roll = roll_die()
+ log("Roll D" + roll + " vs 3-6.")
if (roll >= 3) {
let i = random(enemy_player.hand.length)
let c = enemy_player.hand[i]
enemy_player.hand.splice(i, 1)
player.hand.push(c)
- log(`Stole ${card_name(c)}.`)
+ log(`Took C${c} from opponent.`)
game.state = "courier_intercepted_show"
} else {
log("No effect.")
@@ -7898,7 +7985,7 @@ states.courier_intercepted_roll = {
states.courier_intercepted_show = {
prompt() {
let c = player.hand[player.hand.length-1]
- view.prompt = `Courier Intercepted: You stole ${card_name(c)}.`
+ view.prompt = `Courier Intercepted: You took ${card_name(c)}.`
view.selected_card = c
view.actions.end_event = 1
},
@@ -7925,7 +8012,7 @@ states.francois_bigot_draw = {
set_active_enemy()
let i = random(player.hand.length)
game.bigot = player.hand[i]
- log(`France discarded ${card_name(game.bigot)}.`)
+ log(`France discarded C${game.bigot}.`)
game.state = "francois_bigot_show"
},
}
@@ -7995,6 +8082,7 @@ states.british_ministerial_crisis = {
card(c) {
push_undo()
game.count = 0
+ log(`Britain discarded C${card}.`)
discard_card(c)
},
end_event() {
@@ -8112,8 +8200,8 @@ states.stingy_provincial_assembly = {
},
piece(p) {
push_undo()
- game.count = 0
eliminate_piece(p)
+ game.count = 0
},
end_event() {
set_active_enemy()
@@ -8349,8 +8437,8 @@ states.raise_provincial_regiments = {
push_undo()
let p = find_unused_provincial(game.department)
place_piece(p, s)
- game.count --
game.did_raise = 1
+ game.count --
},
end_event() {
delete game.did_raise
@@ -8463,6 +8551,7 @@ states.colonial_recruits_roll = {
},
roll() {
let roll = roll_die()
+ log("Restore D" + roll + " units.")
game.state = 'colonial_recruits'
game.count = roll
},
@@ -8548,8 +8637,10 @@ states.victories_roll = {
view.actions.roll = 1
},
roll() {
- game.count = roll_die()
+ let roll = roll_die()
+ log("Restore D" + roll + " units.")
game.state = 'restore_regular_or_light_infantry_units'
+ game.count = roll
},
}
@@ -9210,7 +9301,7 @@ states.william_pitt = {
},
card(c) {
push_undo()
- log(`Drew ${card_name(c)} from discard.`)
+ log(`Drew C${c} from discard.`)
remove_from_array(game.discard, c)
player.hand.push(c)
game.count = 0
@@ -9252,7 +9343,7 @@ states.diplomatic_revolution = {
},
card(c) {
push_undo()
- log(`Drew ${card_name(c)} from discard.`)
+ log(`Drew C${c} from discard.`)
remove_from_array(game.discard, c)
player.hand.push(c)
game.count = 0
@@ -9295,7 +9386,7 @@ states.draw_regulars = {
remove_from_array(game.discard, c)
player.hand.push(c)
- log(`Exchanged ${card_name(x)} for ${card_name(c)} in discard.`)
+ log(`Exchanged C${x} for C${c} in discard.`)
start_action_phase()
},
@@ -9713,10 +9804,10 @@ exports.setup = function (seed, scenario, options) {
// go_home: {},
summary: {
- placed: {},
- restored: {},
- reduced: {},
- eliminated: {},
+ placed: [],
+ restored: [],
+ reduced: [],
+ eliminated: [],
},
undo: [],