diff options
Diffstat (limited to 'rules.js')
-rw-r--r-- | rules.js | 157 |
1 files changed, 81 insertions, 76 deletions
@@ -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 === |