diff options
-rw-r--r-- | play.html | 91 | ||||
-rw-r--r-- | play.js | 147 | ||||
-rw-r--r-- | rules.js | 10 |
3 files changed, 201 insertions, 47 deletions
@@ -136,14 +136,19 @@ body.Teutons #plan_actions .russian { display: none } } #battle_grid #grid_ga { - width: 376px; - height: 60px; - display: flex; - justify-content: center; - align-items: center; + height: auto; + min-height: 80px; +} + +#battle_grid #grid_sw { + height: auto; } -#grid_rd1:empty:not(.action), #grid_rd2:empty:not(.action), #grid_rd3:empty:not(.action), +#battle_grid #grid_sw:empty { + display: none; +} + +#grid_rg1:empty:not(.action), #grid_rg2:empty:not(.action), #grid_rg3:empty:not(.action), #grid_sa1:empty:not(.action), #grid_sa2:empty:not(.action), #grid_sa3:empty:not(.action) { display: none; } @@ -157,7 +162,11 @@ body.Teutons #plan_actions .russian { display: none } .defender .att .asset, .attacker .def .asset, .defender .att .service_marker, -.attacker .def .service_marker +.attacker .def .service_marker, +.defender .att .moved_fought, +.attacker .def .moved_fought, +.defender .att .feed_x2, +.attacker .def .feed_x2 { transform: rotate(180deg) } @@ -176,23 +185,25 @@ body.Teutons #plan_actions .russian { display: none } .defender #grid_d1 { grid-row: 3; grid-column: 1; } .defender #grid_d2 { grid-row: 3; grid-column: 2; } .defender #grid_d3 { grid-row: 3; grid-column: 3; } -.defender #grid_rd1 { grid-row: 4; grid-column: 1; } -.defender #grid_rd2 { grid-row: 4; grid-column: 2; } -.defender #grid_rd3 { grid-row: 4; grid-column: 3; } -.defender #grid_sa1 { grid-row: 5; grid-column: 1; } -.defender #grid_sa2 { grid-row: 5; grid-column: 2; } -.defender #grid_sa3 { grid-row: 5; grid-column: 3; } - -.attacker #grid_a1 { grid-row: 5; grid-column: 3; } -.attacker #grid_a2 { grid-row: 5; grid-column: 2; } -.attacker #grid_a3 { grid-row: 5; grid-column: 1; } -.attacker #grid_ga { grid-row: 4; grid-column: 2; } -.attacker #grid_d1 { grid-row: 3; grid-column: 3; } -.attacker #grid_d2 { grid-row: 3; grid-column: 2; } -.attacker #grid_d3 { grid-row: 3; grid-column: 1; } -.attacker #grid_rd1 { grid-row: 2; grid-column: 3; } -.attacker #grid_rd2 { grid-row: 2; grid-column: 2; } -.attacker #grid_rd3 { grid-row: 2; grid-column: 1; } +.defender #grid_rg1 { grid-row: 4; grid-column: 1; } +.defender #grid_rg2 { grid-row: 4; grid-column: 2; } +.defender #grid_rg3 { grid-row: 4; grid-column: 3; } +.defender #grid_sw { grid-row: 5; grid-column: 2; } +.defender #grid_sa1 { grid-row: 6; grid-column: 1; } +.defender #grid_sa2 { grid-row: 6; grid-column: 2; } +.defender #grid_sa3 { grid-row: 6; grid-column: 3; } + +.attacker #grid_a1 { grid-row: 6; grid-column: 3; } +.attacker #grid_a2 { grid-row: 6; grid-column: 2; } +.attacker #grid_a3 { grid-row: 6; grid-column: 1; } +.attacker #grid_ga { grid-row: 5; grid-column: 2; } +.attacker #grid_d1 { grid-row: 4; grid-column: 3; } +.attacker #grid_d2 { grid-row: 4; grid-column: 2; } +.attacker #grid_d3 { grid-row: 4; grid-column: 1; } +.attacker #grid_rg1 { grid-row: 3; grid-column: 3; } +.attacker #grid_rg2 { grid-row: 3; grid-column: 2; } +.attacker #grid_rg3 { grid-row: 3; grid-column: 1; } +.attacker #grid_sw { grid-row: 2; grid-column: 2; } .attacker #grid_sa1 { grid-row: 1; grid-column: 3; } .attacker #grid_sa2 { grid-row: 1; grid-column: 2; } .attacker #grid_sa3 { grid-row: 1; grid-column: 1; } @@ -205,6 +216,17 @@ body.Teutons #plan_actions .russian { display: none } box-shadow: 0 0 0 1px #4e370a, -1px -2px 4px #0008; } +#pursuit { + margin: 0 auto; +} + +.siegeworks { + display: flex; + flex-wrap: wrap; + justify-content: center; + gap: 4px; +} + #garrison { background-repeat: no-repeat; background-position: center; @@ -217,13 +239,11 @@ body.Teutons #plan_actions .russian { display: none } gap: 2px; } +#garrison.hide { display: none } + .attacker #garrison { background-image: url(images/garrison_attacker.svg); } .defender #garrison { background-image: url(images/garrison_defender.svg); } -#garrison:empty { - display: none -} - #garrison .unit { position: static } @@ -426,9 +446,9 @@ body.shift .mustered_vassals { .locale_markers > .conquered + .conquered + .conquered { margin-bottom: 26px; } .locale_markers > .conquered + .conquered + .conquered + .conquered { margin-bottom: 39px; } -.siege + .siege { margin-left: -44px; margin-bottom: 13px; } -.siege + .siege + .siege { margin-bottom: 26px; } -.siege + .siege + .siege + .siege { margin-bottom: 39px; } +.locale_markers .siege + .siege { margin-left: -44px; margin-bottom: 13px; } +.locale_markers .siege + .siege + .siege { margin-bottom: 26px; } +.locale_markers .siege + .siege + .siege + .siege { margin-bottom: 39px; } /* TUCKED CARDS */ @@ -1293,7 +1313,9 @@ body.shift .mustered_vassals { <div id="battle_grid"> <div class="grid_array" id="grid_ga"> <div id="pursuit" class="marker rectangle pursuit russian hide"></div> + <div id="battle_walls1" class="siegeworks"></div> <div id="garrison"></div> + <div id="battle_walls2" class="siegeworks"></div> </div> <div class="grid_array att" id="grid_a1"></div> <div class="grid_array att" id="grid_a2"></div> @@ -1301,9 +1323,10 @@ body.shift .mustered_vassals { <div class="grid_array def" id="grid_d1"></div> <div class="grid_array def" id="grid_d2"></div> <div class="grid_array def" id="grid_d3"></div> - <div class="grid_array att" id="grid_rd1"></div> - <div class="grid_array att" id="grid_rd2"></div> - <div class="grid_array att" id="grid_rd3"></div> + <div class="grid_array att" id="grid_rg1"></div> + <div class="grid_array att" id="grid_rg2"></div> + <div class="grid_array att" id="grid_rg3"></div> + <div class="grid_array siegeworks" id="grid_sw"></div> <div class="grid_array def" id="grid_sa1"></div> <div class="grid_array def" id="grid_sa2"></div> <div class="grid_array def" id="grid_sa3"></div> @@ -32,11 +32,16 @@ function find_card(name) { const R1 = find_card("R1") const T4 = find_card("T4") const T10 = find_card("T10") +const T14 = find_card("T14") const EVENT_RUSSIAN_BRIDGE = R1 const EVENT_TEUTONIC_BRIDGE = T4 const EVENT_TEUTONIC_FIELD_ORGAN = T10 +const AOW_TEUTONIC_TREBUCHETS = T14 + +const RG2 = 10 + const MAP_DPI = 75 const VASSAL_UNAVAILABLE = 0 @@ -575,6 +580,9 @@ const ui = { court1: document.getElementById("court1"), court2: document.getElementById("court2"), garrison: document.getElementById("garrison"), + battle_walls1: document.getElementById("battle_walls1"), + battle_walls2: document.getElementById("battle_walls2"), + battle_siegeworks: document.getElementById("grid_sw"), battle_panel: document.getElementById("battle_panel"), battle_header: document.getElementById("battle_header"), pursuit: document.getElementById("pursuit"), @@ -589,9 +597,9 @@ const ui = { document.getElementById("grid_sa1"), document.getElementById("grid_sa2"), document.getElementById("grid_sa3"), - document.getElementById("grid_rd1"), - document.getElementById("grid_rd2"), - document.getElementById("grid_rd3"), + document.getElementById("grid_rg1"), + document.getElementById("grid_rg2"), + document.getElementById("grid_rg3"), ], castles: [ document.getElementById("castle11"), @@ -1433,6 +1441,70 @@ function update_cards() { } } +function has_castle_marker(loc) { + return ( + set_has(view.pieces.castles1, loc) || + set_has(view.pieces.castles2, loc) + ) +} + +function is_castle(loc) { + return data.locales[loc].type === "castle" || has_castle_marker(loc) +} + +function is_bishopric(loc) { + return data.locales[loc].type === "bishopric" +} + +function has_walls(loc) { + return set_has(view.pieces.walls, loc) +} + +function lord_has_unrouted_units(lord) { + return view.pieces.forces[lord] !== 0 +} + +function get_lord_capability(lord, n) { + return view.pieces.capabilities[(lord << 1) + n] +} + +function lord_has_capability_card(lord, c) { + let name = data.cards[c].capability + let c1 = get_lord_capability(lord, 0) + if (c1 >= 0 && data.cards[c1].capability === name) + return true + let c2 = get_lord_capability(lord, 1) + if (c2 >= 0 && data.cards[c2].capability === name) + return true + return false +} + +function lord_has_capability(lord, card_or_list) { + if (Array.isArray(card_or_list)) { + for (let card of card_or_list) + if (lord_has_capability_card(lord, card)) + return true + return false + } + return lord_has_capability_card(lord, card_or_list) +} + +function attacker_has_trebuchets() { + if (view.battle.attacker === "Teutons") { + for (let lord = first_p1_lord; lord <= last_p1_lord; ++lord) { + if (get_lord_locale(lord) === view.battle.where && lord_has_unrouted_units(lord)) { + if (lord_has_capability(lord, AOW_TEUTONIC_TREBUCHETS)) + return true + } + } + } + return false +} + +function count_siege_markers(loc) { + return map_get(view.pieces.sieges, loc, 0) +} + function update_battle() { let array = view.battle.array @@ -1464,6 +1536,8 @@ function update_battle() { ui.battle_cylinder[lord].classList.toggle("selected", is_lord_selected(lord)) } + ui.garrison.classList.toggle("hide", !view.battle.storm) + ui.garrison.replaceChildren() if (view.battle.garrison) { for (let i = 0; i < view.battle.garrison.knights; ++i) @@ -1471,6 +1545,73 @@ function update_battle() { for (let i = 0; i < view.battle.garrison.men_at_arms; ++i) add_force(ui.garrison, MEN_AT_ARMS, -1, 0) } + + let here = view.battle.where + + let def_prot = 0 + let def_walls = 0 + let att_prot = 0 + let sally_prot = 0 + + if (view.battle.storm) { + if (is_bishopric(here) || is_castle(here)) + def_prot = 4 + else + def_prot = 3 + if (attacker_has_trebuchets()) + def_prot-- + if (has_walls(here)) + def_walls++ + att_prot = count_siege_markers(view.battle.where) + } + + if (view.battle.sally) + def_prot = count_siege_markers(view.battle.where) + if (view.battle.array[RG2] >= 0) + sally_prot = count_siege_markers(view.battle.where) + + let att_ui, def_ui + + if (view.battle.attacker === "Teutons") { + if (player === "Russians") { + att_ui = ui.battle_walls1 + def_ui = ui.battle_walls2 + } else { + att_ui = ui.battle_walls2 + def_ui = ui.battle_walls1 + } + } else { + if (player === "Russians") { + att_ui = ui.battle_walls2 + def_ui = ui.battle_walls1 + } else { + att_ui = ui.battle_walls1 + def_ui = ui.battle_walls2 + } + } + + def_ui.replaceChildren() + for (let i = 0; i < def_prot; ++i) + if (view.battle.attacker === "Teutons") + def_ui.appendChild(get_cached_element("marker square russian siege")) + else + def_ui.appendChild(get_cached_element("marker square teutonic siege")) + for (let i = 0; i < def_walls; ++i) + def_ui.appendChild(get_cached_element("marker square walls")) + + ui.battle_siegeworks.replaceChildren() + for (let i = 0; i < sally_prot; ++i) + if (view.battle.attacker === "Teutons") + ui.battle_siegeworks.appendChild(get_cached_element("marker square russian siege")) + else + ui.battle_siegeworks.appendChild(get_cached_element("marker square teutonic siege")) + + att_ui.replaceChildren() + for (let i = 0; i < att_prot; ++i) + if (view.battle.attacker === "Teutons") + att_ui.appendChild(get_cached_element("marker square teutonic siege")) + else + att_ui.appendChild(get_cached_element("marker square russian siege")) } function is_lord_in_grid(lord) { @@ -2,19 +2,9 @@ // TODO: Bridge - kn, sgt, 1x lh, maa, militia, serf, lh, ah -// PLESKAU: Enemy Lords Removed marker and VP - -// TODO: feed x2 marker -// TODO: end marker - // FIXME: lift_sieges / besieged needs checking! (automatic after disband_lord, manual after move/sail, extra careful manual after battle) // FIXME: remove_legate_if_endangered needs checking! (automatic after disband_lord, manual after move/sail, manual after battle) -// GUI: siegeworks markers for walls and siegeworks (colored by side) -// GUI: show moved/fought markers on mats during Feed phase -// GUI: show sally/relief sally as unbesieged on map -// GUI: show feed x2 on lord mats with > 6 units - // WONTFIX: choose crossbow/normal hit application order // Check all push/clear_undo |