summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js157
1 files changed, 81 insertions, 76 deletions
diff --git a/rules.js b/rules.js
index 95008f4..cd5cc51 100644
--- a/rules.js
+++ b/rules.js
@@ -1,13 +1,5 @@
"use strict"
-// TODO: game end check (no possible attack, no morale left)
-
-// TODO: track routed cards explicitly (separate from retired and pursuit)
-
-// TODO: manual take hits?
-// TODO: manual "enter reserves" ?
-// TODO: manual "pursuit" ?
-
// TODO: allow placing dice on full special formations?
// TODO: fizzle when action says to take cards from other dice?
@@ -285,8 +277,8 @@ function remove_dice(c) {
function eliminate_card(c) {
remove_dice(c)
remove_cubes(c, 3)
- array_remove_item(game.front[0], c)
- array_remove_item(game.front[1], c)
+ set_delete(game.front[0], c)
+ set_delete(game.front[1], c)
}
function pay_for_action(c) {
@@ -818,7 +810,6 @@ states.place = {
states.place_on_card = {
prompt() {
let card = data.cards[game.selected]
- // XXX view.selected = game.selected
view.prompt = "Place dice on " + card.name + "."
gen_place_dice_select_card()
@@ -1151,20 +1142,6 @@ states.bombard = {
},
}
-function format_attack_result() {
- let hits = game.hits
- let self = game.self
- if (hits !== 1 && self > 0)
- return ` ${hits} hits. ${self} self.`
- if (hits === 1 && self > 0)
- return ` ${hits} hit. ${self} self.`
- if (hits !== 1)
- return ` ${hits} hits.`
- if (hits === 1)
- return ` ${hits} hit.`
- return ""
-}
-
function goto_attack(c) {
let a = current_action()
game.state = "attack"
@@ -1175,8 +1152,7 @@ function goto_attack(c) {
states.attack = {
prompt() {
- view.prompt = "Attack " + card_name(game.target) + "." + format_attack_result()
- // XXX view.selected = game.selected
+ view.prompt = "Attack " + card_name(game.target) + "."
gen_action_card(game.target)
view.actions.attack = 1
},
@@ -1211,26 +1187,18 @@ states.command = {
prompt() {
let t = find_target_of_command(current_action())
view.prompt = "Bring " + card_name(t) + " out of reserve."
- // XXX view.selected = game.selected
gen_action_card(t)
},
card(c) {
log(card_name(game.selected) + " commanded " + card_name(c) + " out of reserve.")
let p = player_index()
- array_remove_item(game.reserve[p], c)
+ set_delete(game.reserve[p], c)
set_add(game.front[p], c)
pay_for_action(game.selected)
end_action_phase()
},
}
-function has_reserve_target_routed(reserve) {
- for (let c of reserve)
- if (!set_has(game.front[0], c) && !set_has(game.front[1], c))
- return true
- return false
-}
-
// === REACTION ===
function can_opponent_react() {
@@ -1262,9 +1230,9 @@ function can_take_reaction(c, a) {
default:
throw new Error("invalid reaction: " + a.type)
case "Screen":
- // if any formation is attacked
- // ... by one of the listed targets
- if (!a.target_list.includes(game.selected))
+ // if a friendly formation is attacked by a listed enemy formation
+ // ... or a listed formation is attacked (Wheatfield Road Artillery, etc)
+ if (!a.target_list.includes(game.selected) && !a.target_list.includes(game.target))
return false
break
case "Counterattack":
@@ -1290,9 +1258,7 @@ function can_take_reaction(c, a) {
states.react = {
prompt() {
- view.prompt = card_name(game.selected) + " attacks " + card_name(game.target) + "! " + format_attack_result()
- // XXX view.selected = game.selected
- // XXX view.target = game.target
+ view.prompt = card_name(game.selected) + " attacks " + card_name(game.target) + "!"
let voluntary = true
let p = player_index()
@@ -1576,11 +1542,11 @@ function end_routing() {
}
function find_card_owner(c) {
- if (set_has(game.front[0], c))
+ if (set_has(game.front[0], c) || set_has(game.reserve[0], c))
return 0
- if (set_has(game.front[1], c))
+ if (set_has(game.front[1], c) || set_has(game.reserve[1], c))
return 1
- throw new Error("card not found in any front")
+ throw new Error("card not found in any player area")
}
states.routing = {
@@ -1592,7 +1558,6 @@ states.routing = {
gen_action_card(c)
},
card(c) {
- push_undo() // XXX
if (should_rout_card(c)) {
log(card_name(c) + " routed.")
let p = find_card_owner(c)
@@ -1610,48 +1575,88 @@ states.routing = {
// === PURSUIT ===
+function should_pursue(c) {
+ let pursuit = data.cards[c].pursuit
+ if (pursuit !== undefined)
+ return !set_has(game.front[0], pursuit) && !set_has(game.front[1], pursuit)
+ return false
+}
+
function goto_pursuit() {
- check_pursuit()
+ resume_pursuit()
+}
+
+function resume_pursuit() {
+ game.state = "pursuit"
+ for (let p = 0; p <= 1; ++p)
+ for (let c of game.front[p])
+ if (should_pursue(c))
+ return
+ end_pursuit()
+}
+
+function end_pursuit() {
goto_reserve()
}
-function check_pursuit() {
- // Remove pursuing cards.
- for (let p = 0; p <= 1; ++p) {
- for (let i = 0; i < game.front[p].length; ++i) {
- let c = game.front[p][i]
- let pursuit = data.cards[c].pursuit
- if (pursuit !== undefined) {
- if (!set_has(game.front[1-p], pursuit)) {
- log(card_name(c) + " pursued.")
- eliminate_card(c)
- --i
- }
- }
- }
- }
+states.pursuit = {
+ prompt() {
+ view.prompt = "Pursue cards!"
+ for (let p = 0; p <= 1; ++p)
+ for (let c of game.front[p])
+ if (should_pursue(c))
+ gen_action_card(c)
+ },
+ card(c) {
+ log(card_name(c) + " pursued.")
+ eliminate_card(c)
+ resume_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))
+ return true
+ return false
+}
+
function goto_reserve() {
- check_reserve()
+ resume_reserve()
+}
+
+function resume_reserve() {
+ game.state = "reserve"
+ for (let p = 0; p <= 1; ++p)
+ for (let c of game.reserve[p])
+ if (should_enter_reserve(c))
+ return
+ end_reserve()
+}
+
+function end_reserve() {
goto_roll_phase()
}
-function check_reserve() {
- // Bring on reserves (on both sides).
- for (let p = 0; p <= 1; ++p) {
- for (let i = 0; i < game.reserve[p].length; ++i) {
- let c = game.reserve[p][i]
- if (has_reserve_target_routed(data.cards[c].reserve)) {
- log(card_name(c) + " came out of reserve.")
- set_add(game.front[p], c)
- array_remove(game.reserve[p], i)
- --i
- }
- }
- }
+
+states.reserve = {
+ prompt() {
+ view.prompt = "Enter reserves!"
+ for (let p = 0; p <= 1; ++p)
+ for (let c of game.reserve[p])
+ if (should_enter_reserve(c))
+ gen_action_card(c)
+ },
+ card(c) {
+ log(card_name(c) + " came out of reserve.")
+ let p = find_card_owner(c)
+ set_delete(game.reserve[p], c)
+ set_add(game.front[p], c)
+ resume_reserve()
+ },
}
// === COMMON LIBRARY ===