From 23b5aaf4062756c2d04d7c70af3ee486678aa213 Mon Sep 17 00:00:00 2001 From: Tor Andersson Date: Sat, 14 Sep 2024 15:57:22 +0200 Subject: Make events more forgiving for undo by adding pauses to roll/draw/etc. --- play.css | 13 +++ play.html | 6 +- play.js | 15 +++ rules.js | 329 +++++++++++++++++++++++++++++++++++++++++++++++++++----------- 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 @@
-
-
-
+
+
+
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') -- cgit v1.2.3