diff options
author | Tor Andersson <tor@ccxvii.net> | 2023-12-13 01:19:32 +0100 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2024-01-08 16:36:48 +0100 |
commit | a5368010c02c750d9f14804b9edb381c808d8cac (patch) | |
tree | 12199525f7f2edee1a452a516c0968dd604268eb /rules.js | |
parent | 82bb07f0b44af3268fa1354acdeb2fadfd3c85eb (diff) | |
download | table-battles-a5368010c02c750d9f14804b9edb381c808d8cac.tar.gz |
Attack in reserve. Silver Shields. "Remove" cards after pursuit.
Diffstat (limited to 'rules.js')
-rw-r--r-- | rules.js | 149 |
1 files changed, 109 insertions, 40 deletions
@@ -51,6 +51,7 @@ function find_card(s, n) { } // for (let c of data.cards) for (let a of c.actions) console.log(a.type, a.effect) +// for (let c of data.cards) console.log(c.dice) const P1 = "First" const P2 = "Second" @@ -230,6 +231,10 @@ const S15_WENLOCK = find_card(15, "Wenlock") const S16_STOKE_FIELD = find_scenario(16) +const S22_GABIENE = find_scenario(22) +const S22_EUMENES_CAMP = find_card(22, "Eumenes's Camp") +const S22_SILVER_SHIELDS = find_card(22, "The Silver Shields") + // === SETUP === exports.setup = function (seed, scenario, options) { @@ -1237,7 +1242,7 @@ function is_mandatory_reaction(c, a) { function can_take_action(c, a) { if (a.type === "Attack") { - if (find_target_of_attack(a) < 0) + if (find_target_of_attack(c, a) < 0) return false } @@ -1386,7 +1391,7 @@ function goto_take_action(c, ix) { if (card_has_rule(game.selected, "attack_choose_target")) goto_attack_choose_target() else - goto_attack(find_target_of_attack(a)) + goto_attack(find_target_of_attack(c, a)) break case "Bombard": game.state = "bombard" @@ -1401,12 +1406,19 @@ function current_action() { return data.cards[game.selected].actions[game.action] } -function find_target_of_attack(a) { +function find_target_of_attack(c, a) { + let in_res = card_has_rule(c, "attack_reserve") for (let c of a.target_list) { if (set_has(game.front[0], c)) return c if (set_has(game.front[1], c)) return c + if (in_res) { + if (set_has(game.reserve[0], c)) + return c + if (set_has(game.reserve[1], c)) + return c + } } return -1 } @@ -1529,6 +1541,14 @@ function goto_attack(target) { } } + if (game.scenario === S22_GABIENE) { + if (game.target === S22_SILVER_SHIELDS) { + if (is_card_in_play(S22_EUMENES_CAMP)) { + game.hits = Math.min(1, 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")) @@ -1945,17 +1965,21 @@ function get_attack_hits(c, a) { case "1 hit. Warwick Retires upon completing this Attack Action.": case "1 hit. You CHOOSE the target.": case "1 hit. 1 self per action.": + case "1 hit per action. 1 self per action.": 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.": case "1 hit per die (but see below). 1 self per action.": + case "1 hit per die (plus dice from E. Phalanx).": return count_dice_on_card(c) case "1 hit per pair.": 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.": return 1 + count_dice_on_card(c) + case "5 hits.": + return 5 } } @@ -1968,9 +1992,12 @@ function get_attack_self(c, a) { case "1 hit. You CHOOSE the target.": case "1 hit per die.": case "1 hit per die. Ignore first target until it comes out of Reserve.": + case "1 hit per die (plus dice from E. Phalanx).": case "1 hit per pair.": + case "5 hits.": return 0 case "1 hit. 1 self per action.": + case "1 hit per action. 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.": @@ -1981,6 +2008,37 @@ function get_attack_self(c, a) { // === ROUTING === +function find_card_owner(c) { + if (set_has(game.front[0], c) || set_has(game.reserve[0], c)) + return 0 + if (set_has(game.front[1], c) || set_has(game.reserve[1], c)) + return 1 + throw new Error("card not found in any player area") +} + +function should_rout_card(c) { + 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 +} + +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 should_remove_card(c) { let remove_with = card_has_rule(c, "remove_with") if (remove_with) { @@ -2003,22 +2061,6 @@ function should_retire_card(c) { return false } -function should_rout_card(c) { - 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 -} - function goto_routing() { game.routed = [ 0, 0 ] @@ -2045,10 +2087,10 @@ function resume_routing() { game.state = "routing" for (let p = 0; p <= 1; ++p) { for (let c of game.front[p]) - if (should_rout_card(c) || should_remove_card(c) || should_retire_card(c)) + if (should_rout_card(c)) return for (let c of game.reserve[p]) - if (should_rout_card(c) || should_remove_card(c) || should_retire_card(c)) + if (should_rout_card(c)) return } end_routing() @@ -2105,23 +2147,15 @@ function end_routing() { goto_pursuit() } -function find_card_owner(c) { - if (set_has(game.front[0], c) || set_has(game.reserve[0], c)) - return 0 - if (set_has(game.front[1], c) || set_has(game.reserve[1], c)) - return 1 - throw new Error("card not found in any player area") -} - states.routing = { prompt() { - view.prompt = "Rout and remove cards." + view.prompt = "Rout cards!" for (let p = 0; p <= 1; ++p) { for (let c of game.front[p]) - if (should_rout_card(c) || should_remove_card(c) || should_retire_card(c)) + if (should_rout_card(c)) gen_action_card(c) for (let c of game.reserve[p]) - if (should_rout_card(c) || should_remove_card(c) || should_retire_card(c)) + if (should_rout_card(c)) gen_action_card(c) } }, @@ -2142,13 +2176,6 @@ 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() { resume_pursuit() } @@ -2163,7 +2190,7 @@ function resume_pursuit() { } function end_pursuit() { - goto_reserve() + goto_removing() } states.pursuit = { @@ -2181,6 +2208,48 @@ states.pursuit = { }, } +// === REMOVING === + +function goto_removing() { + resume_removing() +} + +function resume_removing() { + game.state = "removing" + for (let p = 0; p <= 1; ++p) { + for (let c of game.front[p]) + if (should_remove_card(c) || should_retire_card(c)) + return + for (let c of game.reserve[p]) + if (should_remove_card(c) || should_retire_card(c)) + return + } + end_removing() +} + +function end_removing() { + goto_reserve() +} + +states.removing = { + prompt() { + view.prompt = "Remove cards!" + for (let p = 0; p <= 1; ++p) { + for (let c of game.front[p]) + if (should_remove_card(c) || should_retire_card(c)) + gen_action_card(c) + for (let c of game.reserve[p]) + if (should_remove_card(c) || should_retire_card(c)) + gen_action_card(c) + } + }, + card(c) { + log(card_name(c) + " removed.") + eliminate_card(c) + resume_removing() + }, +} + // === RESERVE === function should_enter_reserve(c) { |