diff options
author | Tor Andersson <tor@ccxvii.net> | 2024-05-02 22:15:33 +0200 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2024-05-02 22:15:33 +0200 |
commit | f952fd45b3d6c487b8b05a1b58e3eaa792534736 (patch) | |
tree | 29aaae3b06db099f177d28b6b4a6b4677ae6f130 | |
parent | f2f9f1be71e701e09b7a52e2d83d5eb39e97c449 (diff) | |
download | plantagenet-f952fd45b3d6c487b8b05a1b58e3eaa792534736.tar.gz |
reorder battle event/capability functions in file
-rw-r--r-- | images/shield.svg | 1 | ||||
-rw-r--r-- | play.css | 6 | ||||
-rw-r--r-- | play.html | 30 | ||||
-rw-r--r-- | play.js | 25 | ||||
-rw-r--r-- | rules.ts | 562 |
5 files changed, 305 insertions, 319 deletions
diff --git a/images/shield.svg b/images/shield.svg new file mode 100644 index 0000000..52362c1 --- /dev/null +++ b/images/shield.svg @@ -0,0 +1 @@ +<svg xmlns="http://www.w3.org/2000/svg" height="512px" width="512px" viewBox="0 0 512 512"><path d="M259.303 23.195C191.17 23.188 122.745 33.57 54.896 54.732l-6.12 2.825-.303 6.52c0 95.313 9.696 178.568 40.297 249.96s82.32 130.185 165.277 174.62l4.672 2.337 4.087-2.336C343.87 445.236 396.29 386.753 427.5 315.205c31.21-71.547 41.465-155.484 41.465-251.13V57.07l-6.424-2.336c-67.16-21.138-135.104-31.53-203.237-31.537z"/></svg> @@ -7,8 +7,8 @@ body.Lancaster header.your_turn { background-color: hsl(355, 83%, 72%); } #turn_info { background-color: gray; } .panel_header { background-color: hsl(34, 10%, 30%); } -body.York #event_header, body.York #plan_header, .court_panel.york .panel_header { background-color: hsl(217, 15%, 33%); } -body.Lancaster #event_header, body.Lancaster #plan_header, .court_panel.lancaster .panel_header { background-color: hsl(355, 15%, 33%); } +body.York #event_header, body.York #hand_header, body.York #plan_header, .court_panel.york .panel_header { background-color: hsl(217, 15%, 33%); } +body.Lancaster #event_header, body.Lancaster #hand_header, body.Lancaster #plan_header, .court_panel.lancaster .panel_header { background-color: hsl(355, 15%, 33%); } /* LOG */ @@ -330,7 +330,7 @@ body.Lancaster #plan_actions .york { display: none } gap: 4px; } -#pieces .marker { +#map .marker { position: absolute; } @@ -32,6 +32,7 @@ <li class="debug separator"> </menu> </details> + <button onclick="toggle_seats()"><img src="images/shield.svg"></button> <button onclick="toggle_pieces()"><img src="/images/earth-africa-europe.svg"></button> </div> </header> @@ -62,19 +63,21 @@ <div id="map"> <div id="locales"></div> -<div id="boxes"></div> + +<div id="seats"></div> <div id="pieces"> - <div id="turn" class="marker circle turn levy"></div> - <div id="end" class="marker circle end"></div> - <div id="victory_check" class="marker square victory_check"></div> - <div id="towns" class="marker square towns"></div> - <div id="cities" class="marker square cities"></div> - <div id="fortresses" class="marker square fortresses"></div> - <div id="ip" class="marker square ip"></div> <div id="battle" class="hide" style="z-index:50"></div> </div> +<div id="turn" class="marker circle turn levy"></div> +<div id="end" class="marker circle end"></div> +<div id="victory_check" class="marker square victory_check"></div> +<div id="towns" class="marker square towns"></div> +<div id="cities" class="marker square cities"></div> +<div id="fortresses" class="marker square fortresses"></div> +<div id="ip" class="marker square ip"></div> + </div> </div> @@ -102,16 +105,6 @@ </div> </div> -<div id="reserves_panel" class="panel hide"> -<div id="reserves_header" class="panel_header">Reserves</div> -<div id="reserves" class="panel_body court_body"></div> -</div> - -<div id="routed_panel" class="panel hide"> -<div id="routed_header" class="panel_header">Routed / Fled</div> -<div id="routed" class="panel_body court_body"></div> -</div> - <div id="arts_of_war_panel" class="panel hide"> <div id="arts_of_war_header" class="panel_header">Arts of War</div> <div id="arts_of_war" class="panel_body"></div> @@ -229,7 +222,6 @@ <div data-card="L36" class="card aow lancaster c72"><div class="event"><div class="title">Talbot to the Rescue</div><div class="text"><b>Hold:</b> Play upon Death check to Disband any Routed Lancastrians instead of rolling for Death.</div></div><div class="capability sh3"><div class="title">Chevaliers</div><div class="subtitle">French knights</div><div class="text">This Lord’s Men-at-Arms suffer -1 Armour against Missiles but Melee Strike x2.</div></div><div class="number">L36</div></div> <div data-card="L37" class="card aow lancaster c73"><div class="event"><div class="title">The Earl of Richmond</div><div class="subtitle">is with a mighty power landed at Milford</div><div class="text"><b>This Levy</b><br>Lancastrian Vassal Levy always succeeds.</div></div><div class="capability sh3"><div class="title">Madame La Grande</div><div class="subtitle">Louis XI's daughter Anne finances Tudors</div><div class="text">Each Pay segment (3.2) that this Lord at or adjacent to a Friendly English Channel Port, he receives 1 Coin.</div></div><div class="number">L37</div></div> - <!-- END CARD DATA --> </div> @@ -6,6 +6,10 @@ function toggle_pieces() { document.getElementById("pieces").classList.toggle("hide") } +function toggle_seats() { + document.getElementById("seats").classList.toggle("hide") +} + // === CONSTANTS (matching those in rules.js) === function find_lord(name) { return data.lords.findIndex((x) => x.name === name) } @@ -366,7 +370,6 @@ const ui = { cards: [], cards2: [], lords2: [], - calendar: [], seat: [], plan_panel: document.getElementById("plan_panel"), @@ -600,7 +603,7 @@ function build_map() { //e.style.transform = "rotate(315deg)" e.style.zIndex = "-50" register_tooltip(e, data.lords[ix].short_name) - document.getElementById("pieces").appendChild(e) + document.getElementById("seats").appendChild(e) }) data.lords.forEach((lord, ix) => { @@ -653,22 +656,8 @@ function build_map() { register_tooltip(e, data.vassals[ix].name) }) - for (let i = 1; i <= 16; ++i) { - let name = "box" + i - let x = calendar_boxes[name][0] - let y = calendar_boxes[name][1] - let w = calendar_boxes[name][2] - let h = calendar_boxes[name][3] - calendar_xy[i] = [ x, y, w, h ] - - let e = ui.calendar[i] = document.createElement("div") - e.className = "calendar box " + name - e.style.left = x + "px" - e.style.top = y + "px" - e.style.width = w + "px" - e.style.height = h + "px" - document.getElementById("boxes").appendChild(e) - } + for (let i = 1; i <= 16; ++i) + calendar_xy[i] = calendar_boxes["box" + i] for (let i = 0; i <= 45; ++i) { let name = "track" + i @@ -4287,6 +4287,7 @@ function end_sail() { // Disbanded in battle! if (!is_lord_on_map(game.command)) { + game.group = null clear_flag(FLAG_MARCH_TO_PORT) clear_flag(FLAG_SAIL_TO_PORT) spend_all_actions() @@ -4977,6 +4978,7 @@ function end_march() { // Disbanded in battle! if (!is_lord_on_map(game.command)) { + game.group = null clear_flag(FLAG_MARCH_TO_PORT) clear_flag(FLAG_SAIL_TO_PORT) spend_all_actions() @@ -6245,123 +6247,6 @@ states.ravine = { }, } -// === BATTLE EVENT: REGROUP === - -function is_regroup_in_play() { - if (is_event_in_play(EVENT_YORK_REGROUP)) { - for (let p of battle_strike_positions) { - let lord = game.battle.array[p] - if (is_york_lord(lord) && lord_has_routed_troops(lord) && get_lord_forces(lord, RETINUE)) - return true - } - } - return false -} - -function goto_regroup() { - set_active(YORK) - game.state = "regroup" -} - -states.regroup = { - prompt() { - for (let p of battle_strike_positions) { - let lord = game.battle.array[p] - if (is_york_lord(lord) && lord_has_routed_troops(lord) && get_lord_forces(lord, RETINUE)) - gen_action_lord(lord) - } - if (game.battle.step >= 2) { - view.prompt = "Regroup: You may choose a lord to regroup." - view.actions.pass = 1 - } else { - view.prompt = "Regroup: Choose a lord to regroup." - } - }, - lord(lord) { - push_undo() - logevent(EVENT_YORK_REGROUP) - logi("L" + lord) - game.who = lord - game.state = "regroup_roll_protection" - game.event_regroup = [ - 0, - 0, - get_lord_routed_forces(lord, MEN_AT_ARMS), - get_lord_routed_forces(lord, LONGBOWMEN), - get_lord_routed_forces(lord, MILITIA), - get_lord_routed_forces(lord, BURGUNDIANS), - get_lord_routed_forces(lord, MERCENARIES), - ] - }, - pass() { - goto_battle_lord_rout() - }, -} - -states.regroup_roll_protection = { - prompt() { - view.prompt = "Regroup: Roll each routed troop's protection for them to recover." - if (game.event_regroup[MEN_AT_ARMS] > 0) - gen_action_routed_men_at_arms(game.who) - if (game.event_regroup[LONGBOWMEN] > 0) - gen_action_routed_longbowmen(game.who) - if (game.event_regroup[MILITIA] > 0) - gen_action_routed_militia(game.who) - if (game.event_regroup[BURGUNDIANS] > 0) - gen_action_routed_burgundians(game.who) - if (game.event_regroup[MERCENARIES] > 0) - gen_action_routed_mercenaries(game.who) - }, - routed_burgundians(lord) { - action_regroup(lord, BURGUNDIANS) - }, - routed_mercenaries(lord) { - action_regroup(lord, MERCENARIES) - }, - routed_longbowmen(lord) { - action_regroup(lord, LONGBOWMEN) - }, - routed_men_at_arms(lord) { - action_regroup(lord, MEN_AT_ARMS) - }, - routed_militia(lord) { - action_regroup(lord, MILITIA) - }, -} - -function action_regroup(lord: Lord, type: Force) { - let protection = get_modified_protection(lord, type) - - let die = roll_die() - if (die <= protection) { - logi(`${get_force_name(lord, type)} ${range(protection)}: W${die}`) - add_lord_routed_forces(lord, type, -1) - add_lord_forces(lord, type, 1) - } else { - logi(`${get_force_name(lord, type)} ${range(protection)}: B${die}`) - } - - game.event_regroup[type]-- - - for (let i = 2; i < 7; ++i) - if (game.event_regroup[i] > 0) - return - end_regroup() -} - -function end_regroup() { - // remove event from play once used - set_delete(game.events, EVENT_YORK_REGROUP) - - game.who = NOBODY - delete game.event_regroup - - if (game.battle.step < 2) - game.state = "assign_hits" - else - goto_battle_lord_rout() -} - // === BATTLE EVENT: CALTROPS === states.caltrops = { @@ -6582,48 +6467,160 @@ function is_leeward_battle_line_in_play(lord: Lord) { return false } -// === BATTLE EVENT: SWIFT MANEUVER === +// === BATTLE EVENT: REGROUP === -states.swift_maneuver_1 = { - get inactive() { - view.engaged = game.battle.engagements[0] - return format_strike_step() - }, +function is_regroup_in_play() { + if (is_event_in_play(EVENT_YORK_REGROUP)) { + for (let p of battle_strike_positions) { + let lord = game.battle.array[p] + if (is_york_lord(lord) && lord_has_routed_troops(lord) && get_lord_forces(lord, RETINUE)) + return true + } + } + return false +} + +function goto_regroup() { + set_active(YORK) + game.state = "regroup" +} + +states.regroup = { prompt() { - view.prompt = "Swift Maneuver: Reroll routed retinue?" - view.actions.pass = 1 - gen_action_routed_retinue(game.who) + for (let p of battle_strike_positions) { + let lord = game.battle.array[p] + if (is_york_lord(lord) && lord_has_routed_troops(lord) && get_lord_forces(lord, RETINUE)) + gen_action_lord(lord) + } + if (game.battle.step >= 2) { + view.prompt = "Regroup: You may choose a lord to regroup." + view.actions.pass = 1 + } else { + view.prompt = "Regroup: Choose a lord to regroup." + } }, - routed_retinue(lord) { - action_spend_valour(lord, RETINUE) - if (lord_has_routed_retinue(lord)) - this.pass() - else - finish_action_assign_hits() + lord(lord) { + push_undo() + logevent(EVENT_YORK_REGROUP) + logi("L" + lord) + game.who = lord + game.state = "regroup_roll_protection" + game.event_regroup = [ + 0, + 0, + get_lord_routed_forces(lord, MEN_AT_ARMS), + get_lord_routed_forces(lord, LONGBOWMEN), + get_lord_routed_forces(lord, MILITIA), + get_lord_routed_forces(lord, BURGUNDIANS), + get_lord_routed_forces(lord, MERCENARIES), + ] }, pass() { - game.battle.reroll = 0 - set_active_enemy() - game.state = "swift_maneuver_2" + goto_battle_lord_rout() }, } -states.swift_maneuver_2 = { - inactive: "Swift Maneuver", +states.regroup_roll_protection = { prompt() { - view.prompt = "Swift Maneuver: You may end the battle round immediately." - view.actions.end_battle_round = 1 - view.actions.pass = 1 + view.prompt = "Regroup: Roll each routed troop's protection for them to recover." + if (game.event_regroup[MEN_AT_ARMS] > 0) + gen_action_routed_men_at_arms(game.who) + if (game.event_regroup[LONGBOWMEN] > 0) + gen_action_routed_longbowmen(game.who) + if (game.event_regroup[MILITIA] > 0) + gen_action_routed_militia(game.who) + if (game.event_regroup[BURGUNDIANS] > 0) + gen_action_routed_burgundians(game.who) + if (game.event_regroup[MERCENARIES] > 0) + gen_action_routed_mercenaries(game.who) }, - end_battle_round() { - logevent(EVENT_YORK_SWIFT_MANEUVER) - set_active_enemy() - goto_battle_lord_rout() + routed_burgundians(lord) { + action_regroup(lord, BURGUNDIANS) }, - pass() { - set_active_enemy() - finish_action_assign_hits() + routed_mercenaries(lord) { + action_regroup(lord, MERCENARIES) + }, + routed_longbowmen(lord) { + action_regroup(lord, LONGBOWMEN) }, + routed_men_at_arms(lord) { + action_regroup(lord, MEN_AT_ARMS) + }, + routed_militia(lord) { + action_regroup(lord, MILITIA) + }, +} + +function action_regroup(lord: Lord, type: Force) { + let protection = get_modified_protection(lord, type) + + let die = roll_die() + if (die <= protection) { + logi(`${get_force_name(lord, type)} ${range(protection)}: W${die}`) + add_lord_routed_forces(lord, type, -1) + add_lord_forces(lord, type, 1) + } else { + logi(`${get_force_name(lord, type)} ${range(protection)}: B${die}`) + } + + game.event_regroup[type]-- + + for (let i = 2; i < 7; ++i) + if (game.event_regroup[i] > 0) + return + end_regroup() +} + +function end_regroup() { + // remove event from play once used + set_delete(game.events, EVENT_YORK_REGROUP) + + game.who = NOBODY + delete game.event_regroup + + if (game.battle.step < 2) + game.state = "assign_hits" + else + goto_battle_lord_rout() +} + +// === 4.4.2 BATTLE ROUNDS === + +/* + + for each round (until one side is fully routed) + flee (defender) + flee (attacker) + reposition (defender) + reposition (attacker) + determine engagements + VANGUARD (round 1 only) + for each engagement + archery strike + total hits + assign hits (defender then attacker) + SWIFT MANEUVER - skip to check lord rout + melee strike + total hits + FINAL CHARGE + assign hits (defender then attacker) + SWIFT MANEUVER - skip to check lord rout + check lord rout (defender then attacker) + REGROUP + +*/ + +function goto_battle_rounds() { + log_h4(`Battle Round ${game.battle.round}`) + + game.battle.step = 0 + + if (game.battle.round === 1) { + set_active_defender() + goto_culverins_and_falconets() + } else { + goto_flee() + } } // === BATTLE CAPABILITY: CULVERINS AND FALCONETS === @@ -6718,138 +6715,6 @@ function use_culverins(lord: Lord) { return 0 } -// === BATTLE CAPABILITY: FINAL CHARGE === - -function can_final_charge() { - // If LORD_RICHARD_III with RETINUE in engagement before melee strike. - if (is_melee_step()) { - for (let pos of game.battle.engagements[0]) { - let lord = game.battle.array[pos] - if (lord === LORD_RICHARD_III && get_lord_forces(lord, RETINUE) > 0) - return true - } - } - return false -} - -states.final_charge = { - prompt() { - view.prompt = "Final Charge: Retinue may suffer +1 hit to add +3 extra hits against enemy." - view.actions.final_charge = 1 - view.actions.pass = 1 - }, - final_charge() { - logcap(AOW_YORK_FINAL_CHARGE) - log_hits("+3", lord_name[find_lord_with_capability_card(AOW_YORK_FINAL_CHARGE)]) - log_hits("+1", "Final Charge") - game.battle.final_charge = 1 - if (game.battle.attacker === YORK) { - game.battle.ahits += 1 - game.battle.dhits += 3 - } else { - game.battle.ahits += 3 - game.battle.dhits += 1 - } - goto_defender_assign_hits() - }, - pass() { - goto_defender_assign_hits() - }, -} - -// === BATTLE CAPABILITY: VANGUARD === - -function is_vanguard_in_battle() { - for (let eng of game.battle.engagements) { - for (let p of eng) { - let lord = game.battle.array[p] - if (lord !== NOBODY) { - if (lord_has_capability(lord, AOW_YORK_VANGUARD)) - return true - } - } - } - return false -} - -states.vanguard = { - get inactive() { - let lord = find_lord_with_capability_card(AOW_YORK_VANGUARD) - let p = get_lord_array_position(lord) - for (let eng of game.battle.engagements) - if (eng.includes(p)) - view.engaged = eng - return "Vanguard" - }, - prompt() { - view.prompt = "Vanguard: Norfolk may choose his engagement to be the only one." - - let lord = find_lord_with_capability_card(AOW_YORK_VANGUARD) - let p = get_lord_array_position(lord) - for (let eng of game.battle.engagements) - if (eng.includes(p)) - view.engaged = eng - - view.actions.vanguard = 1 - view.actions.pass = 1 - }, - vanguard() { - let lord = find_lord_with_capability_card(AOW_YORK_VANGUARD) - - // Filter out engagements that don't contain Vanguard lord - game.battle.engagements = game.battle.engagements.filter(engagement => { - for (let p of engagement) - if (game.battle.array[p] === lord) - return true - return false - }) - - goto_select_engagement() - }, - pass() { - goto_select_engagement() - }, -} - -// === 4.4.2 BATTLE ROUNDS === - -/* - - for each round (until one side is fully routed) - flee (defender) - flee (attacker) - reposition (defender) - reposition (attacker) - determine engagements - VANGUARD (round 1 only) - for each engagement - archery strike - total hits - assign hits (defender then attacker) - SWIFT MANEUVER - skip to check lord rout - melee strike - total hits - FINAL CHARGE - assign hits (defender then attacker) - SWIFT MANEUVER - skip to check lord rout - check lord rout (defender then attacker) - REGROUP - -*/ - -function goto_battle_rounds() { - log_h4(`Battle Round ${game.battle.round}`) - - game.battle.step = 0 - - if (game.battle.round === 1) { - set_active_defender() - goto_culverins_and_falconets() - } else { - goto_flee() - } -} - // === 4.4.2 BATTLE ROUNDS: FLEE === function goto_flee() { @@ -7195,6 +7060,60 @@ function end_engagement() { goto_select_engagement() } +// === BATTLE CAPABILITY: VANGUARD === + +function is_vanguard_in_battle() { + for (let eng of game.battle.engagements) { + for (let p of eng) { + let lord = game.battle.array[p] + if (lord !== NOBODY) { + if (lord_has_capability(lord, AOW_YORK_VANGUARD)) + return true + } + } + } + return false +} + +states.vanguard = { + get inactive() { + let lord = find_lord_with_capability_card(AOW_YORK_VANGUARD) + let p = get_lord_array_position(lord) + for (let eng of game.battle.engagements) + if (eng.includes(p)) + view.engaged = eng + return "Vanguard" + }, + prompt() { + view.prompt = "Vanguard: Norfolk may choose his engagement to be the only one." + + let lord = find_lord_with_capability_card(AOW_YORK_VANGUARD) + let p = get_lord_array_position(lord) + for (let eng of game.battle.engagements) + if (eng.includes(p)) + view.engaged = eng + + view.actions.vanguard = 1 + view.actions.pass = 1 + }, + vanguard() { + let lord = find_lord_with_capability_card(AOW_YORK_VANGUARD) + + // Filter out engagements that don't contain Vanguard lord + game.battle.engagements = game.battle.engagements.filter(engagement => { + for (let p of engagement) + if (game.battle.array[p] === lord) + return true + return false + }) + + goto_select_engagement() + }, + pass() { + goto_select_engagement() + }, +} + // === 4.4.2 BATTLE ROUNDS: TOTAL HITS (ROUND UP) === function goto_total_hits() { @@ -7254,6 +7173,45 @@ function log_hits(total, name) { logi(`${total} ${name}`) } +// === BATTLE CAPABILITY: FINAL CHARGE === + +function can_final_charge() { + // If LORD_RICHARD_III with RETINUE in engagement before melee strike. + if (is_melee_step()) { + for (let pos of game.battle.engagements[0]) { + let lord = game.battle.array[pos] + if (lord === LORD_RICHARD_III && get_lord_forces(lord, RETINUE) > 0) + return true + } + } + return false +} + +states.final_charge = { + prompt() { + view.prompt = "Final Charge: Retinue may suffer +1 hit to add +3 extra hits against enemy." + view.actions.final_charge = 1 + view.actions.pass = 1 + }, + final_charge() { + logcap(AOW_YORK_FINAL_CHARGE) + log_hits("+3", lord_name[find_lord_with_capability_card(AOW_YORK_FINAL_CHARGE)]) + log_hits("+1", "Final Charge") + game.battle.final_charge = 1 + if (game.battle.attacker === YORK) { + game.battle.ahits += 1 + game.battle.dhits += 3 + } else { + game.battle.ahits += 3 + game.battle.dhits += 1 + } + goto_defender_assign_hits() + }, + pass() { + goto_defender_assign_hits() + }, +} + // === 4.4.2 BATTLE ROUNDS: ROLL BY HIT (PROTECTION ROLL, VALOUR RE-ROLL, FORCES ROUT) === function goto_defender_assign_hits() { @@ -7596,6 +7554,50 @@ function finish_action_assign_hits() { goto_defender_assign_hits() } +// === BATTLE EVENT: SWIFT MANEUVER === + +states.swift_maneuver_1 = { + get inactive() { + view.engaged = game.battle.engagements[0] + return format_strike_step() + }, + prompt() { + view.prompt = "Swift Maneuver: Reroll routed retinue?" + view.actions.pass = 1 + gen_action_routed_retinue(game.who) + }, + routed_retinue(lord) { + action_spend_valour(lord, RETINUE) + if (lord_has_routed_retinue(lord)) + this.pass() + else + finish_action_assign_hits() + }, + pass() { + game.battle.reroll = 0 + set_active_enemy() + game.state = "swift_maneuver_2" + }, +} + +states.swift_maneuver_2 = { + inactive: "Swift Maneuver", + prompt() { + view.prompt = "Swift Maneuver: You may end the battle round immediately." + view.actions.end_battle_round = 1 + view.actions.pass = 1 + }, + end_battle_round() { + logevent(EVENT_YORK_SWIFT_MANEUVER) + set_active_enemy() + goto_battle_lord_rout() + }, + pass() { + set_active_enemy() + finish_action_assign_hits() + }, +} + // === 4.4.2 BATTLE ROUNDS: LORD ROUT === function rout_lord(lord: Lord) { @@ -7625,6 +7627,7 @@ function will_any_friendly_lords_rout() { function goto_battle_lord_rout() { game.battle.step = 3 + game.who = NOBODY if (is_regroup_in_play()) { goto_regroup() @@ -7865,6 +7868,7 @@ states.battle_losses = { action_losses(lord, MILITIA) }, done() { + game.who = NOBODY end_battle_losses() }, } |