summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.css13
-rw-r--r--play.html6
-rw-r--r--play.js15
-rw-r--r--rules.js329
4 files changed, 305 insertions, 58 deletions
diff --git a/play.css b/play.css
index 2d58d47..95fbdfe 100644
--- a/play.css
+++ b/play.css
@@ -85,6 +85,10 @@ aside { min-width: 220px; }
box-shadow: 0 0 0 2px yellow;
}
+.card.selected {
+ box-shadow: 0 0 0 2px white;
+}
+
.card.enabled {
cursor: pointer;
}
@@ -435,6 +439,15 @@ body.bevel .event {
height: 128px;
}
+.track {
+ box-sizing: border-box;
+}
+
+.track.highlight {
+ border: 4px solid yellow;
+ box-shadow: inset 0 0 3px black, 0 0 3px black;
+}
+
#season_marker.early { top: 104px; }
#season_marker.late { top: 160px; }
#season_marker.year_1755 { left: 220px; }
diff --git a/play.html b/play.html
index 99e9d6d..6173314 100644
--- a/play.html
+++ b/play.html
@@ -119,9 +119,9 @@
<div class="event" id="event_british_blockhouses"></div>
<div class="event" id="event_french_blockhouses"></div>
</div>
- <div id="bpa_reluctant" onmouseenter="on_focus_bpa(0)" onmouseleave="on_blur_bpa()"></div>
- <div id="bpa_supportive" onmouseenter="on_focus_bpa(1)" onmouseleave="on_blur_bpa()"></div>
- <div id="bpa_enthusiastic" onmouseenter="on_focus_bpa(2)" onmouseleave="on_blur_bpa()"></div>
+ <div class="track" id="bpa_reluctant" onmouseenter="on_focus_bpa(0)" onmouseleave="on_blur_bpa()"></div>
+ <div class="track" id="bpa_supportive" onmouseenter="on_focus_bpa(1)" onmouseleave="on_blur_bpa()"></div>
+ <div class="track" id="bpa_enthusiastic" onmouseenter="on_focus_bpa(2)" onmouseleave="on_blur_bpa()"></div>
<div id="spaces"></div>
<div id="markers">
<div class="marker vps vp_0" id="vp_marker"></div>
diff --git a/play.js b/play.js
index b671484..3973ce6 100644
--- a/play.js
+++ b/play.js
@@ -408,6 +408,9 @@ let ui = {
pieces: document.getElementById("pieces"),
cards: document.getElementById("cards"),
last_card: document.getElementById("last_card"),
+ bpa_reluctant: document.getElementById("bpa_reluctant"),
+ bpa_supportive: document.getElementById("bpa_supportive"),
+ bpa_enthusiastic: document.getElementById("bpa_enthusiastic"),
space_list: [],
}
@@ -1005,6 +1008,10 @@ for (let p = 0; p < pieces.length; ++p)
else
build_unit(p)
+ui.bpa_reluctant.onclick = () => send_action("reluctant")
+ui.bpa_supportive.onclick = () => send_action("supportive")
+ui.bpa_enthusiastic.onclick = () => send_action("enthusiastic")
+
document.getElementById("last_card").addEventListener("mouseenter", on_focus_last_card)
document.getElementById("last_card").addEventListener("mouseleave", on_blur_last_card)
@@ -1388,6 +1395,7 @@ function update_card(id) {
card.element.classList.add('highlight')
else
card.element.classList.remove('highlight')
+ card.element.classList.toggle('selected', id === view.selected_card)
if (view.hand.includes(id))
card.element.classList.add("show")
else
@@ -1440,6 +1448,10 @@ function update_map() {
for (let i = 0; i < pieces.length; ++i)
update_piece(i)
+ ui.bpa_reluctant.classList.toggle("highlight", !!(view.actions && view.actions.reluctant))
+ ui.bpa_supportive.classList.toggle("highlight", !!(view.actions && view.actions.supportive))
+ ui.bpa_enthusiastic.classList.toggle("highlight", !!(view.actions && view.actions.enthusiastic))
+
if (focus && focus.length === 0)
focus = null
@@ -1545,6 +1557,9 @@ function update_map() {
"PASS on playing \"Foul Weather\" for the rest of this ACTION PHASE?"
)
+ action_button("roll", "Roll")
+ action_button("draw", "Draw")
+
action_button("pass", "Pass")
action_button("next", "Next")
action_button("end_construction", "End construction")
diff --git a/rules.js b/rules.js
index 5ff4db0..b34a338 100644
--- a/rules.js
+++ b/rules.js
@@ -714,6 +714,10 @@ function deal_cards() {
}
}
+function has_leader_in_pool() {
+ return game.british.pool.length > 0
+}
+
function draw_leader_from_pool() {
if (game.british.pool.length > 0) {
let i = random(game.british.pool.length)
@@ -7297,16 +7301,11 @@ events.northern_indian_alliance = {
return is_friendly_controlled_space(MONTREAL)
},
play() {
- let roll = roll_die()
- if (game.vp > 4)
- game.count = roll
- else
- game.count = Math.ceil(roll / 2)
if (has_friendly_fort(NIAGARA))
game.alliance = [ 'blue', 'blue-orange' ]
else
game.alliance = [ 'blue' ]
- game.state = 'indian_alliance'
+ game.state = 'indian_alliance_roll'
}
}
@@ -7315,16 +7314,11 @@ events.western_indian_alliance = {
return has_friendly_fort(OHIO_FORKS)
},
play() {
- let roll = roll_die()
- if (game.vp > 4)
- game.count = roll
- else
- game.count = Math.ceil(roll / 2)
if (has_friendly_fort(NIAGARA))
game.alliance = [ 'orange', 'blue-orange' ]
else
game.alliance = [ 'orange' ]
- game.state = 'indian_alliance'
+ game.state = 'indian_alliance_roll'
}
}
@@ -7346,10 +7340,8 @@ events.iroquois_alliance = {
return false
},
play() {
- let roll = roll_die()
- game.count = roll
game.alliance = [ 'gray' ]
- game.state = 'indian_alliance'
+ game.state = 'indian_alliance_roll_gray'
},
}
@@ -7360,6 +7352,33 @@ function find_friendly_unused_indian(s) {
return 0
}
+states.indian_alliance_roll = {
+ prompt() {
+ view.prompt = "Indian Alliance: Roll a die."
+ view.actions.roll = 1
+ },
+ roll() {
+ let roll = roll_die()
+ if (game.vp > 4)
+ game.count = roll
+ else
+ game.count = Math.ceil(roll / 2)
+ game.state = 'indian_alliance'
+ },
+}
+
+states.indian_alliance_roll_gray = {
+ prompt() {
+ view.prompt = "Indian Alliance: Roll a die."
+ view.actions.roll = 1
+ },
+ roll() {
+ let roll = roll_die()
+ game.count = roll
+ game.state = 'indian_alliance'
+ },
+}
+
states.indian_alliance = {
prompt() {
let done = true
@@ -7704,6 +7723,16 @@ events.louisbourg_squadrons = {
},
play() {
game.events.no_amphib = 1
+ game.state = "louisbourg_squadrons"
+ },
+}
+
+states.louisbourg_squadrons = {
+ prompt() {
+ view.prompt = "Louisbourg Squadrons: Roll a die."
+ view.actions.roll = 1
+ },
+ roll() {
let roll = roll_die()
log("No amphibious landings this year.")
if (roll <= 3) {
@@ -7712,11 +7741,9 @@ events.louisbourg_squadrons = {
log("Card removed.")
game.events.no_fr_naval = 1
remove_card(LOUISBOURG_SQUADRONS)
- } else {
- log("No effect.")
}
end_action_phase()
- }
+ },
}
events.governor_vaudreuil_interferes = {
@@ -7800,15 +7827,25 @@ states.small_pox = {
},
space(s) {
log(`Small Pox at %${s}.`)
+ game.small_pox = s
+ game.state = "small_pox_roll"
+ },
+}
+
+states.small_pox_roll = {
+ prompt() {
+ view.prompt = "Small Pox: Roll a die."
+ view.actions.roll = 1
+ },
+ roll() {
let roll = roll_die()
- if (count_units_in_space(s) > 8) {
+ if (count_units_in_space(game.small_pox) > 8) {
game.count = roll
} else {
game.count = Math.ceil(roll / 2)
}
log(`Must eliminate ${game.count} steps.`)
game.state = 'small_pox_eliminate_steps'
- game.small_pox = s
set_active_enemy()
},
}
@@ -7883,6 +7920,16 @@ events.courier_intercepted = {
return enemy_player.hand.length > 0
},
play() {
+ game.state = "courier_intercepted_roll"
+ },
+}
+
+states.courier_intercepted_roll = {
+ prompt() {
+ view.prompt = "Courier Intercepted: Roll a die."
+ gen_action("roll")
+ },
+ roll() {
let roll = roll_die()
if (roll >= 3) {
let i = random(enemy_player.hand.length)
@@ -7890,9 +7937,22 @@ events.courier_intercepted = {
enemy_player.hand.splice(i, 1)
player.hand.push(c)
log(`Stole ${card_name(c)}.`)
+ game.state = "courier_intercepted_show"
} else {
log("No effect.")
+ end_action_phase()
}
+ },
+}
+
+states.courier_intercepted_show = {
+ prompt() {
+ let c = player.hand[player.hand.length-1]
+ view.prompt = `Courier Intercepted: You stole ${card_name(c)}.`
+ view.selected_card = c
+ view.actions.next = 1
+ },
+ next() {
end_action_phase()
},
}
@@ -7902,11 +7962,34 @@ events.françois_bigot = {
return enemy_player.hand.length > 0
},
play() {
- let i = random(enemy_player.hand.length)
- let c = enemy_player.hand[i]
- enemy_player.hand.splice(i, 1)
- game.discard.push(c)
- log(`France discarded ${card_name(c)}.`)
+ game.state = "francois_bigot_draw"
+ },
+}
+
+states.francois_bigot_draw = {
+ prompt() {
+ view.prompt = "François Bigot: French player randomly discards a card."
+ view.actions.next = 1
+ },
+ next() {
+ set_active_enemy()
+ let i = random(player.hand.length)
+ game.bigot = player.hand[i]
+ log(`France discarded ${card_name(game.bigot)}.`)
+ game.state = "francois_bigot_show"
+ },
+}
+
+states.francois_bigot_show = {
+ prompt() {
+ view.prompt = `François Bigot: Discard ${card_name(game.bigot)}.`
+ view.actions.card = [ game.bigot ]
+ },
+ card(c) {
+ remove_from_array(player.hand, game.bigot)
+ game.discard.push(game.bigot)
+ delete game.bigot
+ set_active_enemy()
end_action_phase()
},
}
@@ -7918,6 +8001,16 @@ events.british_ministerial_crisis = {
return enemy_player.hand.length > 0
},
play() {
+ game.state = "british_ministerial_crisis_confirm"
+ },
+}
+
+states.british_ministerial_crisis_confirm = {
+ prompt() {
+ view.prompt = "British Ministerial Crisis: Britain must discard one card."
+ view.actions.next = 1
+ },
+ next() {
let n = 0
for (let i = 0; i < enemy_player.hand.length; ++i) {
let c = enemy_player.hand[i]
@@ -8078,6 +8171,14 @@ states.stingy_provincial_assembly = {
},
}
+function pa_name(level) {
+ switch (level) {
+ case RELUCTANT: return "Reluctant"
+ case SUPPORTIVE: return "Supportive"
+ case ENTHUSIASTIC: return "Enthusiastic"
+ }
+}
+
events.british_colonial_politics = {
can_play() {
if (game.active === FRANCE)
@@ -8085,24 +8186,53 @@ events.british_colonial_politics = {
return game.pa < 2
},
play() {
- if (game.active === FRANCE) {
- game.pa -= 1
- log(`Provincial Assemblies reduced to ${pa_name()}.`)
- goto_british_colonial_politics()
- } else {
- game.pa += 1
- log(`Provincial Assemblies increased to ${pa_name()}.`)
- end_action_phase()
- }
+ if (game.active === FRANCE)
+ game.state = "british_colonial_politics_1f"
+ else
+ game.state = "british_colonial_politics_1b"
},
}
-function pa_name() {
- switch (game.pa) {
- case RELUCTANT: return "Reluctant"
- case SUPPORTIVE: return "Supportive"
- case ENTHUSIASTIC: return "Enthusiastic"
- }
+states.british_colonial_politics_1f = {
+ inactive: "British colonial politics",
+ prompt() {
+ view.prompt = `British Colonial Politics: Slide Provincial Assemblies marker to ${pa_name(game.pa-1)}.`
+ if (game.pa === 2)
+ view.actions.supportive = 1
+ else
+ view.actions.reluctant = 1
+ },
+ supportive() {
+ game.pa = SUPPORTIVE
+ log(`Provincial Assemblies reduced to ${pa_name(game.pa)}.`)
+ goto_british_colonial_politics()
+ },
+ reluctant() {
+ game.pa = RELUCTANT
+ log(`Provincial Assemblies reduced to ${pa_name(game.pa)}.`)
+ goto_british_colonial_politics()
+ },
+}
+
+states.british_colonial_politics_1b = {
+ inactive: "British colonial politics",
+ prompt() {
+ view.prompt = `British Colonial Politics: Slide Provincial Assemblies marker to ${pa_name(game.pa+1)}.`
+ if (game.pa === 0)
+ view.actions.supportive = 1
+ else
+ view.actions.enthusiastic = 1
+ },
+ supportive() {
+ game.pa = SUPPORTIVE
+ log(`Provincial Assemblies increased to ${pa_name(game.pa)}.`)
+ end_action_phase()
+ },
+ enthusiastic() {
+ game.pa = ENTHUSIASTIC
+ log(`Provincial Assemblies increased to ${pa_name(game.pa)}.`)
+ end_action_phase()
+ },
}
const southern_provincial_limit = [ 2, 4, 6 ]
@@ -8124,6 +8254,7 @@ function goto_british_colonial_politics() {
}
states.british_colonial_politics = {
+ inactive: "British colonial politics",
prompt() {
let num_s = count_southern_provincials()
let num_n = count_northern_provincials()
@@ -8368,11 +8499,22 @@ function is_colonial_recruit(p) {
events.colonial_recruits = {
can_play() {
for (let p = first_friendly_unit; p <= last_friendly_unit; ++p)
- if (can_restore_unit(p))
- return true
+ if (is_coureurs(p) || is_ranger(p) || is_light_infantry(p) || is_provincial(p))
+ if (can_restore_unit(p))
+ return true
return false
},
play() {
+ game.state = "colonial_recruits_roll"
+ },
+}
+
+states.colonial_recruits_roll = {
+ prompt() {
+ view.prompt = "Colonial Recruits: Roll a die."
+ view.actions.roll = 1
+ },
+ roll() {
let roll = roll_die()
game.state = 'colonial_recruits'
game.count = roll
@@ -8449,8 +8591,18 @@ events.victories_in_germany_release_troops_and_finances_for_new_world = {
return can_restore_regular_or_light_infantry_units()
},
play() {
- game.state = 'restore_regular_or_light_infantry_units'
+ game.state = 'victories_roll'
+ },
+}
+
+states.victories_roll = {
+ prompt() {
+ view.prompt = "Victories in Germany: Roll a die."
+ view.actions.roll = 1
+ },
+ roll() {
game.count = roll_die()
+ game.state = 'restore_regular_or_light_infantry_units'
},
}
@@ -8689,9 +8841,22 @@ states.french_regulars = {
events.light_infantry = {
play() {
- game.state = 'light_infantry'
game.count = 2
+ if (has_leader_in_pool())
+ game.state = 'light_infantry_draw'
+ else
+ game.state = 'light_infantry'
+ },
+}
+
+states.light_infantry_draw = {
+ prompt() {
+ view.prompt = "Light Infantry: Draw a random leader."
+ view.actions.draw = 1
+ },
+ draw() {
game.leader = draw_leader_from_pool()
+ game.state = 'light_infantry'
}
}
@@ -8751,14 +8916,28 @@ events.british_regulars = {
return can_place_in_british_ports()
},
play() {
- game.state = 'british_regulars'
+ game.leader = 0
game.count = 3
- game.leader = draw_leader_from_pool()
if (game.options.regulars_vp && game.year <= 1756)
award_vp(-1)
+ if (has_leader_in_pool())
+ game.state = 'british_regulars_draw'
+ else
+ game.state = 'british_regulars'
}
}
+states.british_regulars_draw = {
+ prompt() {
+ view.prompt = "British Regulars: Draw a random leader."
+ view.actions.draw = 1
+ },
+ draw() {
+ game.leader = draw_leader_from_pool()
+ game.state = "british_regulars"
+ },
+}
+
states.british_regulars = {
prompt() {
if (game.leader) {
@@ -8811,18 +8990,46 @@ events.highlanders = {
game.leader = []
if (card === 60) {
game.count = 4
- for (let i = 0; i < 2; ++i) {
- let p = draw_leader_from_pool()
- if (p)
- game.leader.push(p)
- }
+ if (has_leader_in_pool())
+ game.state = "highlanders_draw_2"
+ else
+ game.state = "highlanders"
} else {
game.count = 1
+ if (has_leader_in_pool())
+ game.state = "highlanders_draw_1"
+ else
+ game.state = "highlanders"
+ }
+ }
+}
+
+states.highlanders_draw_2 = {
+ prompt() {
+ view.prompt = "Highlanders: Draw two random leaders."
+ view.actions.draw = 1
+ },
+ draw() {
+ for (let i = 0; i < 2; ++i) {
let p = draw_leader_from_pool()
if (p)
game.leader.push(p)
}
- }
+ game.state = "highlanders"
+ },
+}
+
+states.highlanders_draw_1 = {
+ prompt() {
+ view.prompt = "Highlanders: Draw a random leader."
+ view.actions.draw = 1
+ },
+ draw() {
+ let p = draw_leader_from_pool()
+ if (p)
+ game.leader.push(p)
+ game.state = "highlanders"
+ },
}
states.highlanders = {
@@ -8877,9 +9084,22 @@ events.royal_americans = {
return false
},
play() {
- game.state = 'royal_americans'
game.count = 4
+ if (has_leader_in_pool())
+ game.state = "royal_americans_draw"
+ else
+ game.state = 'royal_americans'
+ }
+}
+
+states.royal_americans_draw = {
+ prompt() {
+ view.prompt = "Royal Americans: Draw a random leader."
+ view.actions.draw = 1
+ },
+ draw() {
game.leader = draw_leader_from_pool()
+ game.state = 'royal_americans'
}
}
@@ -9673,8 +9893,6 @@ function pop_undo() {
}
function gen_action_undo() {
- if (!view.actions)
- view.actions = {}
if (game.undo && game.undo.length > 0)
view.actions.undo = 1
else
@@ -9834,6 +10052,7 @@ exports.view = function(state, current) {
else
inactive_prompt(game.state.replace(/_/g, " "))
} else {
+ view.actions = {}
states[game.state].prompt()
if (game.active === game.phasing) {
if (game.state !== 'demolish_fort' && game.state !== 'demolish_stockade' && game.state !== 'demolish_fieldworks')