summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js122
1 files changed, 99 insertions, 23 deletions
diff --git a/rules.js b/rules.js
index 4ba0f2a..ca2615b 100644
--- a/rules.js
+++ b/rules.js
@@ -262,7 +262,7 @@ exports.setup = function (seed, scenario, options) {
active: P1,
state: "roll",
- reacted: 0,
+ reacted: -1,
// dice value and position
dice: [
@@ -329,7 +329,7 @@ exports.setup = function (seed, scenario, options) {
map_set(game.cubes, S37_THE_FOG, 3)
}
- goto_action_phase()
+ goto_start_turn()
return game
}
@@ -516,7 +516,7 @@ function is_card_attack_with_target_in_play(c) {
return false
}
-function check_impossible_to_attack_victory() {
+function is_impossible_to_attack() {
let p = player_index()
for (let c of game.front[p])
if (is_card_attack_with_target_in_play(c))
@@ -524,6 +524,24 @@ function check_impossible_to_attack_victory() {
return true
}
+function check_impossible_to_attack_victory() {
+ if (is_impossible_to_attack()) {
+ if (player_index() === 0)
+ return goto_game_over(P2, P1 + " has no more attacks!")
+ else
+ return goto_game_over(P1, P2 + " has no more attacks!")
+ }
+ return false
+}
+
+function check_morale_victory() {
+ if (game.morale[0] === 0)
+ return goto_game_over(P2, P1 + " has run out of morale!")
+ if (game.morale[1] === 0)
+ return goto_game_over(P1, P2 + " has run out of morale!")
+ return false
+}
+
// === ROLL PHASE ===
function is_pool_die(i, v) {
@@ -1041,7 +1059,10 @@ function goto_roll_phase() {
states.roll = {
prompt() {
- view.prompt = "Roll the dice in your pool."
+ if (game.reacted === player_index())
+ view.prompt = "Skipped action phase; roll the dice in your pool."
+ else
+ view.prompt = "Roll the dice in your pool."
view.actions.roll = 1
},
roll() {
@@ -1051,6 +1072,8 @@ states.roll = {
}
function roll_dice_in_pool() {
+ if (game.reacted === player_index())
+ game.reacted = -1
let p = player_index()
for (let i = 0; i < 6; ++i)
if (get_player_dice_location(p, i) < 0)
@@ -1138,8 +1161,7 @@ function end_roll_phase() {
set_player_dice_value(p, i, 0)
set_opponent_active()
-
- goto_action_phase()
+ goto_start_turn()
}
// === ACTION PHASE ===
@@ -1317,17 +1339,60 @@ function can_take_any_action() {
return false
}
-function goto_action_phase() {
- if (check_impossible_to_attack_victory()) {
- if (player_index() === 0)
- goto_game_over(P2, P1 + " has no more attacks!")
- else
- goto_game_over(P1, P2 + " has no more attacks!")
+function count_cards_in_play_from_wing(w) {
+ let n = 0
+ for (let c of game.front[0])
+ if (data.cards[c].wing === w)
+ ++n
+ for (let c of game.front[1])
+ if (data.cards[c].wing === w)
+ ++n
+ for (let c of game.reserve[0])
+ if (data.cards[c].wing === w)
+ ++n
+ for (let c of game.reserve[1])
+ if (data.cards[c].wing === w)
+ ++n
+ return n
+}
+
+function goto_start_turn() {
+ if (check_impossible_to_attack_victory())
return
+
+ if (game.scenario === S25_WHEATFIELD) {
+ // Rout Stony Hill at start of Union turn if it is the only Blue card left.
+ if (player_index() === 1) {
+ if (is_card_in_play(S25_STONY_HILL)) {
+ if (count_cards_in_play_from_wing(BLUE) === 1) {
+ game.state = "stony_hill"
+ return
+ }
+ }
+ }
}
- if (game.reacted) {
- game.reacted = 0
+ goto_action_phase()
+}
+
+states.stony_hill = {
+ prompt() {
+ view.prompt = "Rout Stony Hill!"
+ gen_action_card(S25_STONY_HILL)
+ },
+ card(c) {
+ log("Stony Hill routed!")
+ eliminate_card(S25_STONY_HILL)
+ game.morale[0] --
+ game.morale[1] ++
+ if (check_morale_victory())
+ return
+ goto_action_phase()
+ },
+}
+
+function goto_action_phase() {
+ if (game.reacted === player_index()) {
end_action_phase()
} else {
if (can_take_any_action())
@@ -1866,7 +1931,7 @@ function end_reaction() {
// === SCREEN ===
function goto_screen(c, a) {
- game.reacted = 1
+ game.reacted = player_index()
game.target = c
@@ -1909,7 +1974,7 @@ states.screen = {
// === ABSORB ===
function goto_absorb(c, a) {
- game.reacted = 1
+ game.reacted = player_index()
game.target = c
@@ -1947,7 +2012,7 @@ states.absorb = {
// === COUNTERATTACK ===
function goto_counterattack(c, a) {
- game.reacted = 1
+ game.reacted = player_index()
switch (a.effect)
{
@@ -2029,6 +2094,7 @@ function get_attack_hits(c, a) {
case "1 hit per pair. 1 self per action.":
return count_dice_on_card(c) >> 1
case "1 hit, PLUS 1 hit per die. 1 self per action.":
+ case "1 hit, PLUS 1 hit per die. 1 self per action. Fightin' Irish!":
return 1 + count_dice_on_card(c)
case "5 hits.":
return 5
@@ -2057,6 +2123,7 @@ function get_attack_self(c, a) {
case "1 hit per die. 1 self per action. (But see Semmes.)":
case "1 hit per pair. 1 self per action.":
case "1 hit, PLUS 1 hit per die. 1 self per action.":
+ case "1 hit, PLUS 1 hit per die. 1 self per action. Fightin' Irish!":
return 1
}
}
@@ -2113,6 +2180,14 @@ function should_retire_card(c) {
return false
return true
}
+
+ if (game.scenario === S25_WHEATFIELD) {
+ if (c === S25_ZOOK || c === S25_KELLY) {
+ if (is_card_in_front(S25_WOFFORD))
+ return true
+ }
+ }
+
return false
}
@@ -2169,10 +2244,8 @@ function end_routing() {
game.morale[0] += game.routed[1]
}
}
- if (game.morale[0] === 0)
- return goto_game_over(P2, P1 + " has run out of morale!")
- if (game.morale[1] === 0)
- return goto_game_over(P1, P2 + " has run out of morale!")
+ if (check_morale_victory())
+ return
} else {
// SPECIAL: S3 - Plains of Abraham
// SPECIAL: S34 - Tippermuir - Royalists
@@ -2288,7 +2361,7 @@ function end_removing() {
states.removing = {
prompt() {
- view.prompt = "Remove cards!"
+ view.prompt = "Remove or retire cards!"
for (let p = 0; p <= 1; ++p) {
for (let c of game.front[p])
if (should_remove_card(c) || should_retire_card(c))
@@ -2299,7 +2372,10 @@ states.removing = {
}
},
card(c) {
- log(card_name(c) + " removed.")
+ if (should_retire_card(c))
+ log(card_name(c) + " retired.")
+ else
+ log(card_name(c) + " removed.")
eliminate_card(c)
resume_removing()
},