summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2022-12-22 15:20:48 +0100
committerTor Andersson <tor@ccxvii.net>2023-02-18 13:02:38 +0100
commit469118ad0f0d260b411ad5c57cf5297d90f2af75 (patch)
treebc452c2e9bd5b5bf68ce12000e3a6152a169a4e0
parent61b16996e634fa49cbb3ffd8924f3c0e4fc0f31c (diff)
downloadnevsky-469118ad0f0d260b411ad5c57cf5297d90f2af75.tar.gz
Battle array.
-rw-r--r--play.html129
-rw-r--r--play.js112
-rw-r--r--rules.js246
3 files changed, 398 insertions, 89 deletions
diff --git a/play.html b/play.html
index 53538ae..6ce99c3 100644
--- a/play.html
+++ b/play.html
@@ -146,43 +146,62 @@ body.Teutons #plan_actions .russian { display: none }
#battle.defender { background-image: url(images/mat_battle_defender.png); }
#battle.attacker { background-image: url(images/mat_battle_attacker.png); }
-#battle.defender #battle_attacker_reserves { width: 356px !important; top: 4px; left: 8px; }
-#battle.defender #battle_attacker_left { top: 96px; left: 32px; }
-#battle.defender #battle_attacker_center { top: 96px; left: 162px; }
-#battle.defender #battle_attacker_right { top: 96px; right: 32px; }
-#battle.defender #battle_defender_garrison { width: 356px !important; top: 172px; left: 8px; }
-#battle.defender #battle_defender_left { top: 220px; left: 32px; }
-#battle.defender #battle_defender_center { top: 220px; left: 162px; }
-#battle.defender #battle_defender_right { top: 220px; right: 32px; }
-#battle.defender #battle_sally_left { bottom: 60px; left: 4px; }
-#battle.defender #battle_sally_center { bottom: 60px; right: 200px; }
-#battle.defender #battle_sally_right { bottom: 60px; right: 4px; }
-#battle.defender #battle_defender_reserves { width: 356px !important; bottom: 4px; left: 8px; }
-
-#battle.attacker #battle_attacker_reserves { width: 356px !important; bottom: 4px; left: 8px; }
-#battle.attacker #battle_attacker_left { bottom: 96px; right: 32px; }
-#battle.attacker #battle_attacker_center { bottom: 96px; left: 162px; }
-#battle.attacker #battle_attacker_right { bottom: 96px; left: 32px; }
-#battle.attacker #battle_defender_garrison { width: 356px !important; bottom: 172px; left: 8px; }
-#battle.attacker #battle_defender_left { bottom: 220px; right: 32px; }
-#battle.attacker #battle_defender_center { bottom: 220px; left: 162px; }
-#battle.attacker #battle_defender_right { bottom: 220px; left: 32px; }
-#battle.attacker #battle_sally_left { top: 60px; right: 4px; }
-#battle.attacker #battle_sally_center { top: 60px; left: 200px; }
-#battle.attacker #battle_sally_right { top: 60px; left: 4px; }
-#battle.attacker #battle_defender_reserves { width: 356px !important; top: 4px; left: 8px; }
+#battle.defender #array_attacker_reserves { top: 4px; left: 8px; }
+#battle.defender #array_attacker_left { top: 96px; left: 32px; }
+#battle.defender #array_attacker_center { top: 96px; left: 162px; }
+#battle.defender #array_attacker_right { top: 96px; right: 32px; }
+#battle.defender #array_defender_garrison { top: 172px; left: 8px; }
+#battle.defender #array_defender_left { top: 220px; left: 32px; }
+#battle.defender #array_defender_center { top: 220px; left: 162px; }
+#battle.defender #array_defender_right { top: 220px; right: 32px; }
+#battle.defender #array_sally_left { bottom: 60px; left: 4px; }
+#battle.defender #array_sally_center { bottom: 60px; right: 200px; }
+#battle.defender #array_sally_right { bottom: 60px; right: 4px; }
+#battle.defender #array_defender_reserves { bottom: 4px; left: 8px; }
+
+#battle.attacker #array_attacker_reserves { bottom: 4px; left: 8px; }
+#battle.attacker #array_attacker_left { bottom: 96px; right: 32px; }
+#battle.attacker #array_attacker_center { bottom: 96px; left: 162px; }
+#battle.attacker #array_attacker_right { bottom: 96px; left: 32px; }
+#battle.attacker #array_defender_garrison { bottom: 172px; left: 8px; }
+#battle.attacker #array_defender_left { bottom: 220px; right: 32px; }
+#battle.attacker #array_defender_center { bottom: 220px; left: 162px; }
+#battle.attacker #array_defender_right { bottom: 220px; left: 32px; }
+#battle.attacker #array_sally_left { top: 60px; right: 4px; }
+#battle.attacker #array_sally_center { top: 60px; left: 200px; }
+#battle.attacker #array_sally_right { top: 60px; left: 4px; }
+#battle.attacker #array_defender_reserves { top: 4px; left: 8px; }
#battle > div {
position: absolute;
- width: 48px;
- height: 48px;
display: flex;
flex-wrap: wrap;
justify-content: center;
align-items: center;
+}
+
+#battle .reserves {
+ width: 356px;
+ height: 48px;
+ gap: 8px;
+}
+
+#battle .garrison {
+ width: 356px;
+ height: 48px;
gap: 2px;
}
+#battle .array {
+ width: 48px;
+ height: 48px;
+}
+
+#battle .array.action {
+ border-radius: 50%;
+ box-shadow: 0 0 0 3px white;
+}
+
#battle .cylinder, #battle .unit {
position: static
}
@@ -1208,49 +1227,19 @@ body.shift .mustered_vassals {
<div id="hand" class="hand"></div>
-<div id="battle" class="defender">
-<div id="battle_attacker_reserves">
-<div class="cylinder lord teutonic knud_and_abel"></div>
-<div class="cylinder lord teutonic rudolf"></div>
-</div>
-<div id="battle_attacker_right">
-<div class="cylinder lord teutonic andreas"></div>
-</div>
-<div id="battle_attacker_center">
-<div class="cylinder lord teutonic heinrich"></div>
-</div>
-<div id="battle_attacker_left">
-<div class="cylinder lord teutonic hermann"></div>
-</div>
-<div id="battle_defender_garrison">
-<div class="unit knights"></div>
-<div class="unit men_at_arms"></div>
-<div class="unit men_at_arms"></div>
-<div class="unit men_at_arms"></div>
-</div>
-<div id="battle_defender_left">
-<div class="cylinder lord russian aleksandr"></div>
-</div>
-<div id="battle_defender_center">
-<div class="cylinder lord russian andrey"></div>
-</div>
-<div id="battle_defender_right">
-<div class="cylinder lord russian domash"></div>
-</div>
-<div id="battle_defender_reserves">
-<div class="cylinder lord russian gavrilo"></div>
-<div class="cylinder lord russian karelians"></div>
-<div class="cylinder lord russian vladislav"></div>
-</div>
-<div id="battle_sally_left">
-<div class="cylinder lord teutonic yaroslav"></div>
-</div>
-<div id="battle_sally_center">
-<div class="cylinder lord teutonic yaroslav"></div>
-</div>
-<div id="battle_sally_right">
-<div class="cylinder lord teutonic yaroslav"></div>
-</div>
+<div id="battle" class="attacker">
+<div class="garrison" id="array_defender_garrison"></div>
+<div class="reserves" id="array_attacker_reserves"></div>
+<div class="reserves" id="array_defender_reserves"></div>
+<div class="array" id="array_attacker_right"></div>
+<div class="array" id="array_attacker_center"></div>
+<div class="array" id="array_attacker_left"></div>
+<div class="array" id="array_defender_left"></div>
+<div class="array" id="array_defender_center"></div>
+<div class="array" id="array_defender_right"></div>
+<div class="array" id="array_sally_left"></div>
+<div class="array" id="array_sally_center"></div>
+<div class="array" id="array_sally_right"></div>
</div>
</div>
diff --git a/play.js b/play.js
index ca5433d..ace0b53 100644
--- a/play.js
+++ b/play.js
@@ -55,6 +55,17 @@ const SLED = 4
const BOAT = 5
const SHIP = 6
+// battle array
+const ARRAY_ATK_C = 0
+const ARRAY_DEF_C = 1
+const ARRAY_SALLY_C = 2
+const ARRAY_ATK_L = 3
+const ARRAY_DEF_R = 4
+const ARRAY_SALLY_R = 5
+const ARRAY_ATK_R = 6
+const ARRAY_DEF_L = 7
+const ARRAY_SALLY_L = 8
+
const VECHE = 100
const on_click_asset = [
@@ -167,6 +178,14 @@ function is_lord_action(lord) {
return !!(view.actions && view.actions.lord && set_has(view.actions.lord, lord))
}
+function is_battle_lord_action(lord) {
+ return !!(view.actions && view.actions.battle_lord && set_has(view.actions.battle_lord, lord))
+}
+
+function is_battle_array_action(ix) {
+ return !!(view.actions && view.actions.array && set_has(view.actions.array, ix))
+}
+
function is_asset_action(lord, action) {
return !!(view.actions && view.actions[action] && set_has(view.actions[action], lord))
}
@@ -248,6 +267,13 @@ function restart_cache() {
}
}
+function is_attacking_lord(lord) {
+ if (view.battle.attacker === "Teutons")
+ return lord < 6
+ else
+ return lord >= 6
+}
+
function is_p1_locale(loc) {
return loc >= first_p1_locale && loc <= last_p1_locale
}
@@ -419,6 +445,7 @@ const ui = {
locale_name: [],
locale_markers: [],
lord_cylinder: [],
+ battle_cylinder: [],
lord_service: [],
lord_mat: [],
lord_buttons: [],
@@ -450,6 +477,21 @@ const ui = {
turn: document.getElementById("turn"),
vp1: document.getElementById("vp1"),
vp2: document.getElementById("vp2"),
+ battle_attacker_reserves: document.getElementById("array_attacker_reserves"),
+ battle_defender_reserves: document.getElementById("array_defender_reserves"),
+ battle_garrison: document.getElementById("array_defender_garrison"),
+ battle: document.getElementById("battle"),
+ battle_array: [
+ document.getElementById("array_attacker_center"),
+ document.getElementById("array_defender_center"),
+ document.getElementById("array_sally_center"),
+ document.getElementById("array_attacker_left"),
+ document.getElementById("array_defender_right"),
+ document.getElementById("array_sally_right"),
+ document.getElementById("array_attacker_right"),
+ document.getElementById("array_defender_left"),
+ document.getElementById("array_sally_left"),
+ ],
}
let locale_layout = []
@@ -501,6 +543,13 @@ function on_click_cylinder(evt) {
}
}
+function on_click_battle_cylinder(evt) {
+ if (evt.button === 0) {
+ let id = evt.target.my_id
+ send_action('battle_lord', id)
+ }
+}
+
function on_click_card(evt) {
if (evt.button === 0) {
let id = evt.target.my_id
@@ -616,6 +665,11 @@ function on_click_legate(evt) {
send_action('legate')
}
+function on_click_array(evt) {
+ if (evt.button === 0)
+ send_action('array', evt.target.my_id)
+}
+
function on_blur(evt) {
document.getElementById("status").textContent = ""
}
@@ -1221,6 +1275,29 @@ function update_cards() {
}
}
+function update_battle() {
+ let array = view.battle.array
+ ui.battle_attacker_reserves.replaceChildren()
+ ui.battle_defender_reserves.replaceChildren()
+ for (let i = 0; i < array.length; ++i) {
+ let lord = array[i]
+ ui.battle_array[i].replaceChildren()
+ if (lord >= 0)
+ ui.battle_array[i].appendChild(ui.battle_cylinder[lord])
+ ui.battle_array[i].classList.toggle("action", is_battle_array_action(i))
+ }
+ for (let lord of view.battle.reserves) {
+ if (is_attacking_lord(lord))
+ ui.battle_attacker_reserves.appendChild(ui.battle_cylinder[lord])
+ else
+ ui.battle_defender_reserves.appendChild(ui.battle_cylinder[lord])
+ }
+ for (let lord = 0; lord < 12; ++lord) {
+ ui.battle_cylinder[lord].classList.toggle("action", is_battle_lord_action(lord))
+ ui.battle_cylinder[lord].classList.toggle("selected", view.who === lord)
+ }
+}
+
function on_update() {
restart_cache()
@@ -1293,6 +1370,16 @@ function on_update() {
ui.veche.classList.toggle("action", is_veche_action())
+ if (view.battle) {
+ if (view.battle.attacker === player)
+ ui.battle.className = "attacker"
+ else
+ ui.battle.className = "defender"
+ update_battle()
+ } else {
+ ui.battle.className = "hide"
+ }
+
// Misc
action_button("left", "Left")
action_button("right", "Right")
@@ -1337,22 +1424,27 @@ function on_update() {
action_button("hold", "Hold")
action_button("play", "Play")
+ action_button("concede", "Concede")
+ action_button("battle", "Battle")
+
action_button("end_actions", "End actions")
- action_button("end_wastage", "End wastage")
- action_button("end_plow_and_reap", "End plow and reap")
+ action_button("end_array", "End array")
action_button("end_avoid_battle", "End avoid battle")
action_button("end_call_to_arms", "End call to arms")
action_button("end_disband", "End disband")
- action_button("end_discard", "End discard")
+ action_button("end_disband", "End disband")
action_button("end_feed", "End feed")
action_button("end_levy", "End levy")
action_button("end_muster", "End muster")
action_button("end_pay", "End pay")
action_button("end_plan", "End plan")
+ action_button("end_plow_and_reap", "End plow and reap")
action_button("end_ransom", "End ransom")
+ action_button("end_remove", "End remove")
action_button("end_setup", "End setup")
action_button("end_spoils", "End spoils")
action_button("end_supply", "End supply")
+ action_button("end_wastage", "End wastage")
action_button("end_withdraw", "End withdraw")
action_button("pass", "Pass")
@@ -1536,6 +1628,13 @@ function build_map() {
e.addEventListener("mouseleave", on_blur)
document.getElementById("pieces").appendChild(e)
+ e = ui.battle_cylinder[ix] = document.createElement("div")
+ e.className = "cylinder lord " + clean_name(lord.side) + " " + clean_name(lord.name)
+ e.my_id = ix
+ e.addEventListener("mousedown", on_click_battle_cylinder)
+ e.addEventListener("mouseenter", on_focus_cylinder)
+ e.addEventListener("mouseleave", on_blur)
+
e = ui.lord_service[ix] = document.createElement("div")
e.className = "service_marker lord image" + lord.image + " " + clean_name(lord.side) + " " + clean_name(lord.name) + " hide"
e.my_id = ix
@@ -1584,6 +1683,11 @@ function build_map() {
build_plan()
+ for (let i = 0; i < ui.battle_array.length; ++i) {
+ ui.battle_array[i].my_id = i
+ ui.battle_array[i].addEventListener("mousedown", on_click_array)
+ }
+
for (let c = 0; c < 21; ++c)
build_card("teutonic", c)
for (let c = 21; c < 42; ++c)
@@ -1591,6 +1695,4 @@ function build_map() {
}
build_map()
-// drag_element_with_mouse("#battle", "#battle_header")
-drag_element_with_mouse("#arts_of_war", "#arts_of_war_header")
scroll_with_middle_mouse("main")
diff --git a/rules.js b/rules.js
index 4318fd1..ad21604 100644
--- a/rules.js
+++ b/rules.js
@@ -1,6 +1,8 @@
"use strict"
// clean up game.who (use only in muster / events, not for command)
+// TODO: remove push_state/pop_state stuff - use explicit substates with common functions instead
+// game.levy/command instead of game.who for levy (like game.command for campaign)
// TEST: legate removal during battle and retreats etc
@@ -17,8 +19,6 @@
// TODO: SALLY
// TODO: STORM
-// TODO: remove push_state/pop_state stuff - use explicit substates with common functions instead
-
const data = require("./data.js")
const TODO = false
@@ -89,6 +89,17 @@ const SLED = 4
const BOAT = 5
const SHIP = 6
+// battle array
+const ARRAY_AC = 0
+const ARRAY_DC = 1
+const ARRAY_SC = 2
+const ARRAY_AL = 3
+const ARRAY_DR = 4
+const ARRAY_SR = 5
+const ARRAY_AR = 6
+const ARRAY_DL = 7
+const ARRAY_SL = 8
+
const asset_type_name = [ "prov", "coin", "loot", "cart", "sled", "boat", "ship" ]
function find_card(name) {
@@ -3450,6 +3461,15 @@ function remove_legate_if_endangered(here) {
function march_with_group_3() {
let here = get_lord_locale(game.command)
+ // Disbanded in battle!
+ if (here === NOWHERE) {
+ game.march = 0
+ spend_all_actions()
+ resume_actions()
+ update_supply()
+ return
+ }
+
remove_legate_if_endangered(here)
if (is_besieged_friendly_stronghold(here)) {
@@ -4678,6 +4698,17 @@ function goto_smerdi() {
// === BATTLE ===
+function set_active_attacker() {
+ set_active(game.battle.attacker)
+}
+
+function set_active_defender() {
+ if (game.battle.attacker === P1)
+ set_active(P2)
+ else
+ set_active(P1)
+}
+
function goto_battle() {
if (has_unbesieged_enemy_lord(game.march.to))
start_battle()
@@ -4695,9 +4726,10 @@ function start_battle() {
attacker: game.active,
conceded: 0,
array: [
- NOBODY, NOBODY, NOBODY, // attacker
- NOBODY, NOBODY, NOBODY, // defender
- NOBODY, NOBODY, NOBODY, // sally
+ game.command,
+ NOBODY, NOBODY,
+ NOBODY, NOBODY, NOBODY,
+ NOBODY, NOBODY, NOBODY,
],
garrison: 0,
reserves: [],
@@ -4707,7 +4739,8 @@ function start_battle() {
for (let lord = first_lord; lord <= last_lord; ++lord)
if (get_lord_locale(lord) === here && !is_lord_besieged(lord))
- set_add(game.battle.reserves, lord)
+ if (lord !== game.command)
+ set_add(game.battle.reserves, lord)
// battle array
// events
@@ -4721,11 +4754,182 @@ function start_battle() {
// roll by hit
// end battle
- log("TODO: Battle...")
+ goto_attacker_battle_array()
+}
+
+// === BATTLE: BATTLE ARRAY ===
- game.battle.conceded = P2
- game.battle.loser = P2
- end_battle()
+function has_reserves() {
+ for (let lord of game.battle.reserves)
+ if (is_friendly_lord(lord))
+ return true
+ return false
+}
+
+function prompt_array_lord() {
+ for (let lord of game.battle.reserves)
+ if (is_friendly_lord(lord))
+ if (lord !== game.who)
+ gen_action_battle_lord(lord)
+}
+
+function action_array_lord(pos) {
+ push_undo_without_who()
+ game.battle.array[pos] = game.who
+ set_delete(game.battle.reserves, game.who)
+ game.who = NOBODY
+}
+
+function action_select_lord(lord) {
+ game.who = lord
+}
+
+function goto_attacker_battle_array() {
+ set_active_attacker()
+ game.state = "attacker_battle_array"
+ game.who = NOBODY
+ if (!has_reserves())
+ goto_defender_battle_array()
+}
+
+states.attacker_battle_array = {
+ prompt() {
+ view.prompt = "Battle Array: Position your lords."
+
+ prompt_array_lord()
+
+ if (game.who !== NOBODY) {
+ if (array[ARRAY_AC] === NOBODY) {
+ gen_action_array(ARRAY_AC)
+ } else {
+ if (array[ARRAY_AL] === NOBODY)
+ gen_action_array(ARRAY_AL)
+ if (array[ARRAY_AR] === NOBODY)
+ gen_action_array(ARRAY_AR)
+ }
+ }
+
+ if (!has_reserves() || (array[ARRAY_AC] >= 0 && array[ARRAY_AL] >= 0 && array[ARRAY_AR] >= 0))
+ view.actions.end_array = 1
+ },
+ battle_lord: action_select_lord,
+ array: action_array_lord,
+ end_array() {
+ clear_undo()
+ goto_defender_battle_array()
+ },
+}
+
+function goto_defender_battle_array() {
+ set_active_defender()
+ game.state = "defender_battle_array"
+ game.who = NOBODY
+ if (!has_reserves())
+ goto_attacker_events()
+}
+
+states.defender_battle_array = {
+ prompt() {
+ view.prompt = "Battle Array: Position your lords."
+
+ let array = game.battle.array
+
+ prompt_array_lord()
+
+ if (game.who !== NOBODY) {
+ if (array[ARRAY_DC] === NOBODY) {
+ gen_action_array(ARRAY_DC)
+ } else if (array[ARRAY_AL] !== NOBODY && array[ARRAY_AR] === NOBODY && array[ARRAY_DL] === NOBODY) {
+ gen_action_array(ARRAY_DL)
+ } else if (array[ARRAY_AR] !== NOBODY && array[ARRAY_AL] === NOBODY && array[ARRAY_DR] === NOBODY) {
+ gen_action_array(ARRAY_DR)
+ } else {
+ if (array[ARRAY_DL] !== NOBODY)
+ gen_action_array(ARRAY_DL)
+ if (array[ARRAY_DR] === NOBODY)
+ gen_action_array(ARRAY_DR)
+ }
+ }
+
+ if (!has_reserves() || (array[ARRAY_DC] >= 0 && array[ARRAY_DL] >= 0 && array[ARRAY_DR] >= 0))
+ view.actions.end_array = 1
+ },
+ battle_lord: action_select_lord,
+ array: action_array_lord,
+ end_array() {
+ clear_undo()
+ goto_attacker_events()
+ },
+}
+
+function goto_attacker_events() {
+ log("TODO attacker events")
+ goto_defender_events()
+}
+
+function goto_defender_events() {
+ log("TODO defender events")
+ goto_relief_sally()
+}
+
+function goto_relief_sally() {
+ log("TODO relief sally")
+ goto_battle_rounds()
+}
+
+function goto_battle_rounds() {
+ set_active_attacker()
+ goto_concede()
+}
+
+// === BATTLE: CONCEDE THE FIELD ===
+
+function goto_concede() {
+ game.state = "concede"
+}
+
+states.concede = {
+ prompt() {
+ view.prompt = "Battle: Concede the Field?"
+ view.actions.concede = 1
+ view.actions.battle = 1
+ },
+ concede() {
+ log(game.active + " concede.")
+ game.battle.conceded = game.active
+ goto_reposition()
+ },
+ battle() {
+ if (game.battle.storm) {
+ goto_reposition()
+ } else {
+ set_active_enemy()
+ if (game.active === game.attacker)
+ goto_reposition()
+ }
+ }
+}
+
+// === BATTLE: REPOSITION ===
+
+function goto_reposition() {
+ log("TODO reposition")
+ goto_strike()
+}
+
+function goto_strike() {
+ log("TODO strike")
+ goto_new_round()
+}
+
+function goto_new_round() {
+ // TODO: no unrouted lords
+ if (game.battle.conceded) {
+ game.battle.loser = game.battle.conceded
+ end_battle()
+ } else {
+ goto_concede_the_field()
+ }
}
// === ENDING THE BATTLE ===
@@ -4882,6 +5086,7 @@ function can_retreat() {
function goto_retreat() {
let here = game.march.to
+ console.log("goto_retreat", here, count_unbesieged_friendly_lords(here), can_retreat())
if (count_unbesieged_friendly_lords(here) > 0 && can_retreat()) {
game.battle.retreated = []
for (let lord = first_friendly_lord; lord <= last_friendly_lord; ++lord)
@@ -5057,6 +5262,7 @@ states.battle_remove = {
push_undo()
transfer_assets_except_ships(lord)
disband_lord(lord, true)
+ remove_legate_if_endangered(game.battle.where)
},
end_remove() {
push_undo()
@@ -5175,14 +5381,17 @@ states.battle_service = {
function goto_battle_aftermath() {
set_active(game.battle.attacker)
- // Moved/Fought
+ // Moved/Fought - TODO: mark at start of battle instead
for (let lord of game.battle.array)
if (lord !== NOBODY)
- set_lord_moved(lord, 1)
+ if (is_lord_on_map(lord))
+ set_lord_moved(lord, 1)
for (let lord of game.battle.reserves)
- set_lord_moved(lord, 1)
+ if (is_lord_on_map(lord))
+ set_lord_moved(lord, 1)
for (let lord of game.battle.routed)
- set_lord_moved(lord, 1)
+ if (is_lord_on_map(lord))
+ set_lord_moved(lord, 1)
game.battle = 0
@@ -6100,6 +6309,14 @@ function gen_action_lord(lord) {
gen_action("lord", lord)
}
+function gen_action_battle_lord(lord) {
+ gen_action("battle_lord", lord)
+}
+
+function gen_action_array(pos) {
+ gen_action("array", pos)
+}
+
function gen_action_service(service) {
gen_action("service", service)
}
@@ -6156,6 +6373,7 @@ exports.view = function (state, current) {
events: game.events,
capabilities: game.capabilities,
pieces: game.pieces,
+ battle: game.battle,
command: game.command,
hand: null,