summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js102
1 files changed, 81 insertions, 21 deletions
diff --git a/rules.js b/rules.js
index 3e77533..7316a03 100644
--- a/rules.js
+++ b/rules.js
@@ -29,7 +29,7 @@ TODO: extra input steps
*/
-// TODO: allow placing dice on full special formations?
+// TODO: morale cube limit (cannot place on special if maxed)
// TODO: fizzle when action says to take cards from other dice?
const data = require("./data.js")
@@ -196,6 +196,14 @@ const S8_CLINTON = find_card(8, "Clinton")
const S8_GRANT = find_card(8, "Grant")
const S8_HESSIANS = find_card(8, "Hessians")
+const S37_INKERMAN = find_scenario(37)
+const S37_PAULOFFS_LEFT = find_card(37, "Pauloff's Left")
+const S37_PAULOFFS_RIGHT = find_card(37, "Pauloff's Right")
+const S37_BRITISH_TROOPS = find_card(37, "British Troops")
+const S37_FRENCH_TROOPS = find_card(37, "French Troops")
+const S37_SOIMONOFF = find_card(37, "Soimonoff")
+const S37_THE_FOG = find_card(37, "The Fog")
+
// === SETUP ===
exports.setup = function (seed, scenario, options) {
@@ -271,6 +279,10 @@ exports.setup = function (seed, scenario, options) {
log(".h2 " + info.date)
log("")
+ if (game.scenario === S37_INKERMAN) {
+ map_set(game.cubes, S37_THE_FOG, 3)
+ }
+
goto_action_phase()
return game
@@ -319,7 +331,7 @@ function add_cubes(c, n) {
function remove_cubes(c, n) {
let old = map_get(game.cubes, c, 0)
- map_set(game.cubes, c, Math.min(0, old - n))
+ map_set(game.cubes, c, Math.max(0, old - n))
}
function add_sticks(c, n) {
@@ -423,9 +435,6 @@ function check_impossible_to_attack_victory() {
for (let c of game.front[p])
if (is_card_attack_with_target_in_play(c))
return false
- for (let c of game.reserve[p])
- if (is_card_attack_with_target_in_play(c))
- return false
return true
}
@@ -1119,10 +1128,15 @@ function is_mandatory_reaction(c, a) {
}
function can_take_action(c, a) {
- if (a.type === "Attack" && find_target_of_attack(a) < 0)
- return false
- if (a.type === "Command" && find_first_target_of_command(a) < 0)
- return false
+ if (a.type === "Attack") {
+ if (find_target_of_attack(a) < 0)
+ return false
+ }
+
+ if (a.type === "Command") {
+ if (find_first_target_of_command(c, a) < 0)
+ return false
+ }
if (game.scenario === S8_BROOKLYN_HEIGHTS) {
if (c === S8_CLINTON) {
@@ -1259,7 +1273,7 @@ function goto_take_action(c, ix) {
game.state = "bombard"
break
case "Command":
- game.state = "command"
+ goto_command()
break
}
}
@@ -1278,12 +1292,18 @@ function find_target_of_attack(a) {
return -1
}
-function find_first_target_of_command(a) {
- for (let c of a.target_list) {
- if (set_has(game.reserve[0], c))
- return c
- if (set_has(game.reserve[1], c))
- return c
+function find_first_target_of_command(c, a) {
+
+ if (game.scenario === S37_INKERMAN) {
+ if (c === S37_THE_FOG)
+ return S37_THE_FOG
+ }
+
+ for (let t of a.target_list) {
+ if (set_has(game.reserve[0], t))
+ return t
+ if (set_has(game.reserve[1], t))
+ return t
}
return -1
}
@@ -1332,6 +1352,13 @@ function goto_attack() {
}
}
+ if (game.scenario === S37_INKERMAN) {
+ // Until the first Fog Cube is lifted.
+ if (map_get(game.cubes, S37_THE_FOG, 0) === 3) {
+ game.hits -= 1
+ }
+ }
+
if (card_has_rule(game.target, "suffer_1_less_1_max"))
game.hits = Math.max(0, Math.min(1, game.hits - 1))
if (card_has_rule(game.target, "suffer_1_less"))
@@ -1366,6 +1393,22 @@ function resume_attack() {
end_action_phase()
}
+// === COMMAND ===
+
+function goto_command() {
+
+ if (game.scenario === S37_INKERMAN && game.selected === S37_THE_FOG) {
+ log("The Fog Lifts...")
+ remove_cubes(S37_THE_FOG, 1)
+ remove_dice(game.selected)
+ end_action_phase()
+ return
+ }
+
+ game.state = "command"
+}
+
+
states.command = {
prompt() {
let list = find_all_targets_of_command(current_action())
@@ -1388,7 +1431,14 @@ states.command = {
}
}
- if (find_first_target_of_command(current_action())) {
+ if (game.scenario === S37_INKERMAN) {
+ if (c === S37_PAULOFFS_LEFT) {
+ log("Morale Cube added to Russian side.")
+ game.morale[0] += 1
+ }
+ }
+
+ if (find_first_target_of_command(game.selected, current_action()) < 0) {
pay_for_action(game.selected)
end_action_phase()
}
@@ -1672,6 +1722,7 @@ function get_attack_hits(c, a) {
return 1
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.":
return count_dice_on_card(c)
case "1 hit per pair.":
case "1 hit per pair. 1 self per action.":
@@ -1687,6 +1738,7 @@ function get_attack_self(c, a) {
throw new Error("invalid attack effect: " + a.effect)
case "1 hit.":
case "1 hit per die.":
+ case "1 hit per die. Ignore first target until it comes out of Reserve.":
case "1 hit per pair.":
return 0
case "1 hit. 1 self per action.":
@@ -1877,10 +1929,18 @@ states.pursuit = {
// === RESERVE ===
-function should_enter_reserve(rc) {
- let reserve = data.cards[rc].reserve
- for (let c of reserve)
- if (!set_has(game.front[0], c) && !set_has(game.front[1], c))
+function should_enter_reserve(c) {
+ let reserve = data.cards[c].reserve
+
+ if (game.scenario === S37_INKERMAN) {
+ if (c === S37_BRITISH_TROOPS)
+ return map_get(game.cubes, S37_THE_FOG, 0) === 1
+ if (c === S37_FRENCH_TROOPS)
+ return map_get(game.cubes, S37_THE_FOG, 0) === 0
+ }
+
+ for (let t of reserve)
+ if (!set_has(game.front[0], t) && !set_has(game.front[1], t))
return true
return false
}