summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--play.html91
-rw-r--r--play.js147
-rw-r--r--rules.js10
3 files changed, 201 insertions, 47 deletions
diff --git a/play.html b/play.html
index 173dfec..41e120f 100644
--- a/play.html
+++ b/play.html
@@ -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>
diff --git a/play.js b/play.js
index 540ad2c..186a403 100644
--- a/play.js
+++ b/play.js
@@ -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) {
diff --git a/rules.js b/rules.js
index a849084..bfd56fa 100644
--- a/rules.js
+++ b/rules.js
@@ -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