summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2023-12-09 19:58:23 +0100
committerTor Andersson <tor@ccxvii.net>2024-01-08 16:36:47 +0100
commit3d4909f946f724562d354a55a721ded43a12c268 (patch)
tree7e6659790356e7c021c51f85b9537f85a8d54d23
parentc5f35f99aa9605a7baf43d6c407b126a51e878f8 (diff)
downloadtable-battles-3d4909f946f724562d354a55a721ded43a12c268.tar.gz
Towton and Edgecote Moor. take_from, rout_with, and remove_with.
-rw-r--r--cards.css10
-rw-r--r--rules.js77
-rw-r--r--tools/gendata.js41
3 files changed, 99 insertions, 29 deletions
diff --git a/cards.css b/cards.css
index a01ead0..06dd919 100644
--- a/cards.css
+++ b/cards.css
@@ -12,6 +12,10 @@
box-shadow: 1px 2px 8px #0008;
}
+.card.scenario {
+ background-color: #eecba1;
+}
+
.card {
user-select: none;
}
@@ -50,7 +54,7 @@
position: absolute;
width: 32px;
height: 16px;
- top: 58px;
+ top: 55px;
background-size: contain;
}
@@ -207,7 +211,6 @@
bottom: 0px;
right: 0px;
padding: 8px 8px;
- opacity: 50%;
}
.extra {
@@ -218,7 +221,6 @@
bottom: 0px;
left: 0px;
padding: 8px 8px;
- opacity: 50%;
}
/* SCENARIO CARD */
@@ -259,6 +261,6 @@
.list{margin:4px;gap:4px!important;}
.card{box-shadow:none!important;border-radius:0!important;}
.card,.scenario_title,.scenario_player,.strength,.action_row *{background-color:white!important}
- .number,.extra{opacity:1!important}
+ .number,.extra{display:block;}
.extra{display:block}
}
diff --git a/rules.js b/rules.js
index 7862704..33b87d8 100644
--- a/rules.js
+++ b/rules.js
@@ -13,12 +13,12 @@ Special card rules implemented:
suffer_1_less_1_max
suffer_1_less
start_with_no_cubes
+ take_from
TODO:
- remove_with
rout_with
+ remove_with
wild
- take_from
attack_reserve
no_morale
@@ -210,6 +210,9 @@ const S3201_DH_HILL = find_card(3201, "D.H. Hill")
const S3201_AP_HILL = find_card(3201, "A.P. Hill")
const S3201_LONGSTREET = find_card(3201, "Longstreet")
+const S12_TOWTON = find_scenario(12)
+const S13_EDGECOTE_MOOR = find_scenario(13)
+
// === SETUP ===
exports.setup = function (seed, scenario, options) {
@@ -296,6 +299,13 @@ exports.setup = function (seed, scenario, options) {
// === GAME STATE ACCESSORS ===
+function count_total_cubes() {
+ let n = game.morale[0] + game.morale[1]
+ for (let i = 1; i < game.cubes.length; i += 2)
+ n += game.cubes[i]
+ return n
+}
+
function card_has_rule(c, name) {
let rules = data.cards[c].rules
if (rules)
@@ -359,6 +369,14 @@ function remove_dice(c) {
}
}
+function move_dice(from, to) {
+ for (let i = 0; i < 12; ++i) {
+ if (get_dice_location(i) === from) {
+ set_dice_location(i, to)
+ }
+ }
+}
+
function eliminate_card(c) {
remove_dice(c)
remove_cubes(c, 3)
@@ -647,10 +665,22 @@ function can_place_dice(c) {
}
// At cube limit?
- if (data.cards[c].special)
+ if (data.cards[c].special) {
+ // Max on card
if (map_get(game.cubes, c, 0) >= data.cards[c].special)
return false
+ // Max available
+ let n_cubes = count_total_cubes()
+ if (n_cubes >= 10)
+ return false
+
+ if (game.scenario === S12_TOWTON) {
+ if (n_cubes >= 8)
+ return false
+ }
+ }
+
// At per wing limit?
let wing = data.cards[c].wing
let n_wing = 0
@@ -1355,7 +1385,11 @@ states.bombard = {
function goto_attack() {
let a = current_action()
- // TODO: 88B German Infantry - take dice from Saxon Infantry
+ let take_from = card_has_rule(game.selected, "take_from")
+ if (take_from) {
+ for (let from of take_from)
+ move_dice(from, game.selected)
+ }
game.state = "attack"
game.target = find_target_of_attack(a)
@@ -1457,6 +1491,18 @@ states.command = {
}
}
+ if (game.scenario === S13_EDGECOTE_MOOR) {
+ // TODO: pay all 3 cubes? remove cards from play?
+ if (game.reserve[0].length === 0 && game.reserve[1].length > 0) {
+ log("Gained a second morale cube.")
+ game.morale[0] += 1
+ }
+ if (game.reserve[1].length === 0 && game.reserve[0].length > 0) {
+ log("Gained a second morale cube.")
+ game.morale[1] += 1
+ }
+ }
+
if (find_first_target_of_command(game.selected, current_action()) < 0) {
pay_for_action(game.selected)
end_action_phase()
@@ -1742,6 +1788,7 @@ function get_attack_hits(c, a) {
case "1 hit per die.":
case "1 hit per die. 1 self per action.":
case "1 hit per die. Ignore first target until it comes out of Reserve.":
+ case "1 hit per die (but see below). 1 self per action.":
return count_dice_on_card(c)
case "1 hit per pair.":
case "1 hit per pair. 1 self per action.":
@@ -1762,6 +1809,7 @@ function get_attack_self(c, a) {
return 0
case "1 hit. 1 self per action.":
case "1 hit per die. 1 self per action.":
+ case "1 hit per die (but see below). 1 self per action.":
case "1 hit per pair. 1 self per action.":
case "1 hit, PLUS 1 hit per die. 1 self per action.":
return 1
@@ -1771,15 +1819,30 @@ function get_attack_self(c, a) {
// === ROUTING ===
function should_remove_card(c) {
- // TODO: remove after X routs special rules
+ let remove_with = card_has_rule(c, "remove_with")
+ if (remove_with) {
+ for (let other of remove_with)
+ if (is_card_in_play(other))
+ return false
+ return true
+ }
+
return false
}
function should_rout_card(c) {
- // TODO: rout after X routs special rules
- if (!data.cards[c].special)
+ if (!data.cards[c].special) {
if (map_get(game.sticks, c, 0) === 0)
return true
+
+ let rout_with = card_has_rule(c, "rout_with")
+ if (rout_with) {
+ for (let other of rout_with)
+ if (is_card_in_play(other))
+ return false
+ return true
+ }
+ }
return false
}
diff --git a/tools/gendata.js b/tools/gendata.js
index 9580130..1bc9099 100644
--- a/tools/gendata.js
+++ b/tools/gendata.js
@@ -75,21 +75,13 @@ for (let c of card_records) {
result.push(`<div class="formation card">`)
result.push(`<div class="name ${c.wing}">${c.name}</div>`)
- if (c.symbol === "Inf1") {
+ if (c.symbol === "inf") {
card.infantry = 1
- result.push(`<div class="symbol infantry1"></div>`)
+ result.push(`<div class="symbol infantry"></div>`)
}
- if (c.symbol === "Inf2") {
- card.infantry = 2
- result.push(`<div class="symbol infantry2"></div>`)
- }
- if (c.symbol === "Cav1") {
+ if (c.symbol === "cav") {
card.cavalry = 1
- result.push(`<div class="symbol cavalry1"></div>`)
- }
- if (c.symbol === "Cav2") {
- card.cavalry = 2
- result.push(`<div class="symbol cavalry2"></div>`)
+ result.push(`<div class="symbol cavalry"></div>`)
}
if (card.strength)
@@ -177,9 +169,7 @@ for (let c of card_records) {
card.retire = 1
else if (c.reserve === "PURSUIT")
card.pursuit = 1
- else if (c.reserve === "Commanded")
- card.reserve = []
- else if (c.reserve === "See Above")
+ else if (c.reserve === "Commanded" || c.reserve === "See Above" || c.reserve === "Special Rule")
card.reserve = []
else
card.reserve = c.reserve.split(" or ")
@@ -242,7 +232,7 @@ function find_wing_cards(scenario, wing) {
}
/* process action and reserve targets */
-for (let c of cards) {
+function process_card(c) {
for (let a of c.actions) {
if (a.target) {
let tname = a.target.replace(" out of reserve", "")
@@ -260,12 +250,16 @@ for (let c of cards) {
a.target_list = find_wing_cards(c.scenario, WING.pink)
else if (tname === "Any Blue formation")
a.target_list = find_wing_cards(c.scenario, WING.blue)
+ else if (tname === "Any Dark Blue formation")
+ a.target_list = find_wing_cards(c.scenario, WING.dkblue)
else if (tname.startsWith("Any attack on "))
a.target_list = tname.replace("Any attack on ", "").split(" or ").map(name => find_card(c.scenario, name))
else if (tname === "Any friendly but Little Round Top")
a.target_list = find_friendly_cards(c.scenario, c.wing).filter(x => x !== find_card(c.scenario, "Little Round Top"))
+ else if (tname === 'Activate "Retreat to Nivelles"')
+ a.target_list = [ "Retreat to Nivelles" ]
else if (tname === "The Fog Lifts...")
- a.target_list = []
+ a.target_list = [ "The Fog" ]
else
a.target_list = tname.split(/, | OR | or | and /).map(name => find_card(c.scenario, name))
}
@@ -286,7 +280,18 @@ for (let c of cards) {
c.reserve = c.reserve.map(name => find_card(c.scenario, name))
}
-fs.writeFileSync("info/all-cards.html", result.join("\n"))
+let failed = false
+for (let c of cards) {
+ try {
+ process_card(c)
+ } catch (err) {
+ console.log(err)
+ failed = true
+ }
+}
+
+if (!failed)
+ fs.writeFileSync("info/all-cards.html", result.join("\n"))
result = [
`<!doctype html>