diff options
author | Tor Andersson <tor@ccxvii.net> | 2022-10-02 17:34:09 +0200 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2022-11-16 19:19:39 +0100 |
commit | c26bd4c55134db4a776ffd1f9f33f8789445aa97 (patch) | |
tree | 0fb53d60da140174b4dd4ed758c2c8d025ce0774 /rules.js | |
parent | a0ee653860e471bba2fb1cd8d7611fd633af9878 (diff) | |
download | crusader-rex-c26bd4c55134db4a776ffd1f9f33f8789445aa97.tar.gz |
No semicolons.
Diffstat (limited to 'rules.js')
-rw-r--r-- | rules.js | 3068 |
1 files changed, 1533 insertions, 1535 deletions
@@ -1,4 +1,4 @@ -"use strict"; +"use strict" // TODO: optional rule - force marches @@ -9,45 +9,46 @@ exports.scenarios = [ "Standard" -]; +] exports.roles = [ "Franks", "Saracens", -]; - -const { CARDS, BLOCKS, TOWNS, PORTS, ROADS, SHIELDS } = require('./data'); - -const FRANKS = "Franks"; -const SARACENS = "Saracens"; -const ASSASSINS = "Assassins"; -const OBSERVER = "Observer"; -const BOTH = "Both"; -const DEAD = "Dead"; -const F_POOL = "FP"; -const S_POOL = "SP"; -const SEA = "Sea"; -const ENGLAND = "England"; -const FRANCE = "France"; -const GERMANIA = "Germania"; -const TYRE = "Tyre"; -const TRIPOLI = "Tripoli"; -const ALEPPO = "Aleppo"; -const ANTIOCH = "Antioch"; -const ST_SIMEON = "St. Simeon"; -const DAMASCUS = "Damascus"; -const MASYAF = "Masyaf"; -const SALADIN = "Saladin"; - -const INTRIGUE = 3; -const WINTER_CAMPAIGN = 6; - -const ENGLISH_CRUSADERS = [ "Richard", "Robert", "Crossbows" ]; -const GERMAN_CRUSADERS = [ "Barbarossa", "Frederik", "Leopold" ]; -const FRENCH_CRUSADERS = [ "Philippe", "Hugues", "Fileps" ]; -const SALADIN_FAMILY = [ "Saladin", "Al Adil", "Al Aziz", "Al Afdal", "Al Zahir" ]; - -const GERMAN_ROADS = [ ST_SIMEON, ANTIOCH, ALEPPO ]; +] + +const { CARDS, BLOCKS, TOWNS, PORTS, ROADS, SHIELDS } = require('./data') + +const FRANKS = "Franks" +const SARACENS = "Saracens" +const ASSASSINS = "Assassins" +const OBSERVER = "Observer" +const BOTH = "Both" +const ELIMINATED = null +const DEAD = "Dead" +const F_POOL = "FP" +const S_POOL = "SP" +const SEA = "Sea" +const ENGLAND = "England" +const FRANCE = "France" +const GERMANIA = "Germania" +const TYRE = "Tyre" +const TRIPOLI = "Tripoli" +const ALEPPO = "Aleppo" +const ANTIOCH = "Antioch" +const ST_SIMEON = "St. Simeon" +const DAMASCUS = "Damascus" +const MASYAF = "Masyaf" +const SALADIN = "Saladin" + +const INTRIGUE = 3 +const WINTER_CAMPAIGN = 6 + +const ENGLISH_CRUSADERS = [ "Richard", "Robert", "Crossbows" ] +const GERMAN_CRUSADERS = [ "Barbarossa", "Frederik", "Leopold" ] +const FRENCH_CRUSADERS = [ "Philippe", "Hugues", "Fileps" ] +const SALADIN_FAMILY = [ "Saladin", "Al Adil", "Al Aziz", "Al Afdal", "Al Zahir" ] + +const GERMAN_ROADS = [ ST_SIMEON, ANTIOCH, ALEPPO ] const KINGDOMS = { Syria: SARACENS, @@ -55,35 +56,35 @@ const KINGDOMS = { Tripoli: FRANKS, Jerusalem: FRANKS, Egypt: SARACENS, -}; +} const VICTORY_TOWNS = [ "Aleppo", "Damascus", "Egypt", "Antioch", "Tripoli", "Acre", "Jerusalem" -]; +] // serif cirled numbers -const DIE_HIT = [ 0, '\u2776', '\u2777', '\u2778', '\u2779', '\u277A', '\u277B' ]; -const DIE_MISS = [ 0, '\u2460', '\u2461', '\u2462', '\u2463', '\u2464', '\u2465' ]; -const DIE_SELF = '\u2716'; +const DIE_HIT = [ 0, '\u2776', '\u2777', '\u2778', '\u2779', '\u277A', '\u277B' ] +const DIE_MISS = [ 0, '\u2460', '\u2461', '\u2462', '\u2463', '\u2464', '\u2465' ] +const DIE_SELF = '\u2716' -const ATTACK_MARK = "*"; -const RESERVE_MARK_1 = "\u2020"; -const RESERVE_MARK_2 = "\u2021"; +const ATTACK_MARK = "*" +const RESERVE_MARK_1 = "\u2020" +const RESERVE_MARK_2 = "\u2021" // Only used by UI layer for layout. remove from game logic. -delete TOWNS[DEAD]; -delete TOWNS[F_POOL]; -delete TOWNS[S_POOL]; -delete TOWNS[SEA]; +delete TOWNS[DEAD] +delete TOWNS[F_POOL] +delete TOWNS[S_POOL] +delete TOWNS[SEA] // Quick lists for fast iteration const BLOCKLIST = Object.keys(BLOCKS) const TOWNLIST = Object.keys(TOWNS) -let states = {}; +let states = {} -let game = null; +let game = null function random(n) { if (game.rng === 1) @@ -92,80 +93,80 @@ function random(n) { } function log(s) { - game.log.push(s); + game.log.push(s) } function active_adjective() { - return (game.active === FRANKS ? "Frank" : "Saracen"); + return (game.active === FRANKS ? "Frank" : "Saracen") } function join(list, conj = "or") { - if (list.length === 0) return ""; - if (list.length === 1) return list[0]; - if (list.length === 2) return `${list[0]} ${conj} ${list[1]}`; - return `${list.slice(0,-1).join(", ")}, ${conj} ${list[list.length-1]}`; + if (list.length === 0) return "" + if (list.length === 1) return list[0] + if (list.length === 2) return `${list[0]} ${conj} ${list[1]}` + return `${list.slice(0,-1).join(", ")}, ${conj} ${list[list.length-1]}` } function log_move_start(from) { - game.move_buf = [ from ]; + game.move_buf = [ from ] } function log_move_continue(to, mark) { if (mark) - game.move_buf.push(to + mark); + game.move_buf.push(to + mark) else - game.move_buf.push(to); + game.move_buf.push(to) } function log_move_end() { if (game.move_buf && game.move_buf.length > 1) - game.summary.push(game.move_buf); - delete game.move_buf; + game.summary.push(game.move_buf) + delete game.move_buf } function print_summary(text, skip_if_empty = false) { - let n = 0; + let n = 0 function print_move(last) { - return "\n" + n + " " + last.join(" \u2192 "); + return "\n" + n + " " + last.join(" \u2192 ") } if (!skip_if_empty || game.summary.length > 0) { - game.summary.sort(); - let last = game.summary[0]; + game.summary.sort() + let last = game.summary[0] for (let entry of game.summary) { if (entry.toString() !== last.toString()) { - text += print_move(last); - n = 0; + text += print_move(last) + n = 0 } - ++n; - last = entry; + ++n + last = entry } if (n > 0) - text += print_move(last); + text += print_move(last) else - text += "\nnothing."; - log(text); + text += "\nnothing." + log(text) } - delete game.summary; + delete game.summary } function enemy(p) { - if (p === FRANKS) return SARACENS; - if (p === SARACENS) return FRANKS; - return null; + if (p === FRANKS) return SARACENS + if (p === SARACENS) return FRANKS + return null } function is_inactive_player(current) { - return current === OBSERVER || (game.active !== current && game.active !== BOTH); + return current === OBSERVER || (game.active !== current && game.active !== BOTH) } function is_winter() { - return game.turn === 6; + return game.turn === 6 } function remove_from_array(array, item) { - let i = array.indexOf(item); + let i = array.indexOf(item) if (i >= 0) - array.splice(i, 1); + array.splice(i, 1) } function deep_copy(original) { @@ -222,9 +223,9 @@ function gen_action_undo(view) { if (!view.actions) view.actions = {} if (game.undo && game.undo.length > 0) - view.actions.undo = 1; + view.actions.undo = 1 else - view.actions.undo = 0; + view.actions.undo = 0 } function gen_action(view, action, argument) { @@ -232,462 +233,462 @@ function gen_action(view, action, argument) { view.actions = {} if (argument !== undefined) { if (!(action in view.actions)) { - view.actions[action] = [ argument ]; + view.actions[action] = [ argument ] } else { if (!view.actions[action].includes(argument)) - view.actions[action].push(argument); + view.actions[action].push(argument) } } else { - view.actions[action] = true; + view.actions[action] = true } } function roll_d6() { - return random(6) + 1; + return random(6) + 1 } function shuffle_deck() { - let deck = []; + let deck = [] for (let c = 1; c <= 27; ++c) - deck.push(c); - return deck; + deck.push(c) + return deck } function deal_cards(deck, n) { - let hand = []; + let hand = [] for (let i = 0; i < n; ++i) { - let k = random(deck.length); - hand.push(deck[k]); - deck.splice(k, 1); + let k = random(deck.length) + hand.push(deck[k]) + deck.splice(k, 1) } - return hand; + return hand } function select_random_block(where) { - let list = []; + let list = [] for (let b of BLOCKLIST) if (game.location[b] === where) - list.push(b); + list.push(b) if (list.length === 0) - return null; - return list[random(list.length)]; + return null + return list[random(list.length)] } function select_random_enemy_block(where) { - let list = []; + let list = [] for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === enemy(game.active)) - list.push(b); + list.push(b) if (list.length === 0) - return null; - return list[random(list.length)]; + return null + return list[random(list.length)] } function block_name(who) { if (BLOCKS[who].type === 'nomads') - return BLOCKS[who].name; - return who; + return BLOCKS[who].name + return who } function block_type(who) { - return BLOCKS[who].type; + return BLOCKS[who].type } function block_home(who) { - let home = BLOCKS[who].home; - if (home === "Normandy") return "England"; - if (home === "Aquitaine") return "England"; - if (home === "Bourgogne") return "France"; - if (home === "Flanders") return "France"; - return home; + let home = BLOCKS[who].home + if (home === "Normandy") return "England" + if (home === "Aquitaine") return "England" + if (home === "Bourgogne") return "France" + if (home === "Flanders") return "France" + return home } function list_seats(who) { switch (block_type(who)) { case 'nomads': - return [ block_home(who) ]; + return [ block_home(who) ] case 'turcopoles': - who = "Turcopoles"; - break; + who = "Turcopoles" + break case 'military_orders': - who = BLOCKS[who].name; - break; + who = BLOCKS[who].name + break } if (is_saladin_family(who)) - who = SALADIN; + who = SALADIN if (who === "Raymond (Tiberias)" || who === "Raymond (Tripoli)") - who = "Raymond"; - let list = []; + who = "Raymond" + let list = [] for (let town in SHIELDS) if (SHIELDS[town].includes(who)) - list.push(town); - return list; + list.push(town) + return list } function is_home_seat(where, who) { if (is_saladin_family(who)) - who = SALADIN; + who = SALADIN switch (block_type(who)) { case 'nomads': - return where === block_home(who); + return where === block_home(who) case 'turcopoles': - who = "Turcopoles"; - break; + who = "Turcopoles" + break case 'military_orders': - who = BLOCKS[who].name; - break; + who = BLOCKS[who].name + break } if (who === "Raymond (Tiberias)" || who === "Raymond (Tripoli)") - who = "Raymond"; + who = "Raymond" if (SHIELDS[where] && SHIELDS[where].includes(who)) - return true; - return false; + return true + return false } function block_pool(who) { if (BLOCKS[who].owner === FRANKS) - return F_POOL; - return S_POOL; + return F_POOL + return S_POOL } function block_owner(who) { - return BLOCKS[who].owner; + return BLOCKS[who].owner } function block_initiative(who) { - return BLOCKS[who].combat[0]; + return BLOCKS[who].combat[0] } function block_fire_power(who) { - return BLOCKS[who].combat[1] | 0; + return BLOCKS[who].combat[1] | 0 } function block_move(who) { - return BLOCKS[who].move; + return BLOCKS[who].move } function block_max_steps(who) { - return BLOCKS[who].steps; + return BLOCKS[who].steps } function is_saladin_family(who) { - return who === "Saladin" || who === "Al Adil" || who === "Al Aziz" || who === "Al Afdal" || who === "Al Zahir"; + return who === "Saladin" || who === "Al Adil" || who === "Al Aziz" || who === "Al Afdal" || who === "Al Zahir" } function is_english_crusader(who) { - return (who === "Richard" || who === "Robert" || who === "Crossbows"); + return (who === "Richard" || who === "Robert" || who === "Crossbows") } function are_crusaders_not_in_pool(crusaders) { for (let b of crusaders) if (game.location[b] === F_POOL) - return false; - return true; + return false + return true } function is_block_on_map(who) { - let location = game.location[who]; - return location && location !== DEAD && location !== F_POOL && location !== S_POOL; + let location = game.location[who] + return location && location !== DEAD && location !== F_POOL && location !== S_POOL } function is_block_on_land(who) { - let location = game.location[who]; + let location = game.location[who] return location && location !== DEAD && location !== F_POOL && location !== S_POOL && - location !== ENGLAND && location !== FRANCE && location !== GERMANIA; + location !== ENGLAND && location !== FRANCE && location !== GERMANIA } function road_id(a, b) { - return (a < b) ? a + "/" + b : b + "/" + a; + return (a < b) ? a + "/" + b : b + "/" + a } function road_was_last_used_by_enemy(from, to) { - return game.last_used[road_id(from, to)] === enemy(game.active); + return game.last_used[road_id(from, to)] === enemy(game.active) } function road_was_last_used_by_friendly(from, to) { - return game.last_used[road_id(from, to)] === game.active; + return game.last_used[road_id(from, to)] === game.active } function road_type(a, b) { - return ROADS[road_id(a,b)]; + return ROADS[road_id(a,b)] } function road_limit(a, b) { - return game.road_limit[road_id(a,b)] || 0; + return game.road_limit[road_id(a,b)] || 0 } function reset_road_limits() { - game.road_limit = {}; + game.road_limit = {} } function count_player(p, where) { - let count = 0; + let count = 0 for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) - ++count; - return count; + ++count + return count } function count_friendly(where) { - let p = game.active; - let count = 0; + let p = game.active + let count = 0 for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) - ++count; - return count; + ++count + return count } function count_enemy(where) { - let p = enemy(game.active); - let count = 0; + let p = enemy(game.active) + let count = 0 for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) - ++count; - return count; + ++count + return count } function count_friendly_in_field(where) { - let p = game.active; - let count = 0; + let p = game.active + let count = 0 for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) if (!is_block_in_castle(b)) - ++count; - return count; + ++count + return count } function count_enemy_in_field(where) { - let p = enemy(game.active); - let count = 0; + let p = enemy(game.active) + let count = 0 for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) if (!is_block_in_castle(b)) - ++count; - return count; + ++count + return count } function count_friendly_in_field_excluding_reserves(where) { - let p = game.active; - let count = 0; + let p = game.active + let count = 0 for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) if (!is_block_in_castle(b) && !is_reserve(b)) - ++count; - return count; + ++count + return count } function count_enemy_in_field_excluding_reserves(where) { - let p = enemy(game.active); - let count = 0; + let p = enemy(game.active) + let count = 0 for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === p) if (!is_block_in_castle(b) && !is_reserve(b)) - ++count; - return count; + ++count + return count } function count_blocks_in_castle(where) { - let n = 0; + let n = 0 for (let b of BLOCKLIST) if (game.location[b] === where && game.castle.includes(b)) - ++n; - return n; + ++n + return n } function count_enemy_in_field_and_reserve(where) { - let n = 0; + let n = 0 for (let b of BLOCKLIST) if (block_owner(b) !== game.active) if (game.location[b] === where && !game.castle.includes(b)) - ++n; - return n; + ++n + return n } function count_reserves(where) { - let n = 0; + let n = 0 for (let b of BLOCKLIST) if (block_owner(b) === game.active) if (game.location[b] === where && is_reserve(b)) - ++n; - return n; + ++n + return n } function is_player_kingdom(p, where) { - return KINGDOMS[TOWNS[where].region] === p; + return KINGDOMS[TOWNS[where].region] === p } function is_friendly_kingdom(where) { - return KINGDOMS[TOWNS[where].region] === game.active; + return KINGDOMS[TOWNS[where].region] === game.active } function is_enemy_kingdom(where) { - return KINGDOMS[TOWNS[where].region] !== game.active; + return KINGDOMS[TOWNS[where].region] !== game.active } /* Town queries include castle and field. */ function is_friendly_town(where) { - return (count_enemy(where) === 0) && (count_friendly(where) > 0 || is_friendly_kingdom(where)); + return (count_enemy(where) === 0) && (count_friendly(where) > 0 || is_friendly_kingdom(where)) } function is_enemy_town(where) { - return (count_friendly(where) === 0) && (count_enemy(where) > 0 || is_enemy_kingdom(where)); + return (count_friendly(where) === 0) && (count_enemy(where) > 0 || is_enemy_kingdom(where)) } function is_vacant_town(where) { - return count_friendly(where) === 0 && count_enemy(where) === 0; + return count_friendly(where) === 0 && count_enemy(where) === 0 } function is_contested_town(where) { - return count_friendly(where) > 0 && count_enemy(where) > 0; + return count_friendly(where) > 0 && count_enemy(where) > 0 } function is_enemy_occupied_town(where) { - return count_enemy(where) > 0; + return count_enemy(where) > 0 } /* Field queries exclude castles. */ function is_friendly_field(where) { - return (count_enemy_in_field(where) === 0) && (count_friendly_in_field(where) > 0 || is_friendly_kingdom(where)); + return (count_enemy_in_field(where) === 0) && (count_friendly_in_field(where) > 0 || is_friendly_kingdom(where)) } function is_enemy_field(where) { - return (count_friendly_in_field(where) === 0) && (count_enemy_in_field(where) > 0 || is_enemy_kingdom(where)); + return (count_friendly_in_field(where) === 0) && (count_enemy_in_field(where) > 0 || is_enemy_kingdom(where)) } function is_contested_field(where) { - return count_friendly_in_field(where) > 0 && count_enemy_in_field(where) > 0; + return count_friendly_in_field(where) > 0 && count_enemy_in_field(where) > 0 } function is_friendly_or_vacant_field(where) { - return is_friendly_field(where) || is_vacant_town(where); + return is_friendly_field(where) || is_vacant_town(where) } function is_enemy_or_contested_field(where) { - return (count_enemy_in_field(where) > 0 || is_enemy_kingdom(where)); + return (count_enemy_in_field(where) > 0 || is_enemy_kingdom(where)) } /* Battle field queries exclude castles and reserves. */ function is_contested_battle_field() { - let f = count_friendly_in_field_excluding_reserves(game.where); - let e = count_enemy_in_field_excluding_reserves(game.where); - return f > 0 && e > 0; + let f = count_friendly_in_field_excluding_reserves(game.where) + let e = count_enemy_in_field_excluding_reserves(game.where) + return f > 0 && e > 0 } function is_friendly_battle_field() { - return count_enemy_in_field_excluding_reserves(game.where) === 0; + return count_enemy_in_field_excluding_reserves(game.where) === 0 } function is_enemy_battle_field() { - return count_friendly_in_field_excluding_reserves(game.where) === 0; + return count_friendly_in_field_excluding_reserves(game.where) === 0 } function is_reserve(who) { - return game.reserves1.includes(who) || game.reserves2.includes(who); + return game.reserves1.includes(who) || game.reserves2.includes(who) } function is_field_attacker(who) { if (game.location[who] === game.where && block_owner(who) === game.attacker[game.where]) - return !is_reserve(who) && !is_block_in_castle(who); - return false; + return !is_reserve(who) && !is_block_in_castle(who) + return false } function is_field_defender(who) { if (game.location[who] === game.where && block_owner(who) !== game.attacker[game.where]) - return !is_reserve(who) && !is_block_in_castle(who); - return false; + return !is_reserve(who) && !is_block_in_castle(who) + return false } function is_field_combatant(who) { if (game.location[who] === game.where) - return !is_reserve(who) && !is_block_in_castle(who); - return false; + return !is_reserve(who) && !is_block_in_castle(who) + return false } function is_block_in_field(who) { - return !is_reserve(who) && !is_block_in_castle(who); + return !is_reserve(who) && !is_block_in_castle(who) } function is_siege_attacker(who) { - return game.storming.includes(who); + return game.storming.includes(who) } function is_siege_defender(who) { - return is_block_in_castle_in(who, game.where); + return is_block_in_castle_in(who, game.where) } function is_siege_combatant(who) { - return game.storming.includes(who) || is_block_in_castle_in(who, game.where); + return game.storming.includes(who) || is_block_in_castle_in(who, game.where) } function castle_limit(where) { - return TOWNS[where].rating; + return TOWNS[where].rating } function is_more_room_in_castle(where) { - return count_blocks_in_castle(where) < castle_limit(where); + return count_blocks_in_castle(where) < castle_limit(where) } function is_within_castle_limit(where) { - return count_friendly(where) <= Math.max(1, castle_limit(where)); + return count_friendly(where) <= Math.max(1, castle_limit(where)) } function is_castle_town(where) { - return castle_limit(where) > 0; + return castle_limit(where) > 0 } function is_under_siege(where) { - return count_blocks_in_castle(where) > 0; + return count_blocks_in_castle(where) > 0 } function is_block_in_castle(b) { - return game.castle.includes(b); + return game.castle.includes(b) } function is_block_in_castle_in(b, town) { - return game.location[b] === town && game.castle.includes(b); + return game.location[b] === town && game.castle.includes(b) } function besieged_player(where) { for (let b of BLOCKLIST) if (is_block_in_castle_in(b, where)) - return block_owner(b); - return null; + return block_owner(b) + return null } function besieging_player(where) { - return enemy(besieged_player(where)); + return enemy(besieged_player(where)) } function is_port(where) { - return TOWNS[where].port; + return TOWNS[where].port } function is_friendly_port(where) { - return TOWNS[where].port && is_friendly_field(where); + return TOWNS[where].port && is_friendly_field(where) } function can_activate(who) { return block_owner(who) === game.active && is_block_on_map(who) && !is_block_in_castle(who) && - !game.moved[who]; + !game.moved[who] } function can_activate_for_sea_move(who) { return block_owner(who) === game.active && is_block_on_map(who) && - !game.moved[who]; + !game.moved[who] } function count_pinning(where) { - return count_enemy_in_field_excluding_reserves(where); + return count_enemy_in_field_excluding_reserves(where) } function count_pinned(where) { - let count = 0; + let count = 0 for (let b of BLOCKLIST) if (game.location[b] === where && block_owner(b) === game.active) if (!is_reserve(b)) - ++count; - return count; + ++count + return count } function is_pinned(who, from) { if (game.active === game.p2) { if (count_pinned(from) <= count_pinning(from)) - return true; + return true } - return false; + return false } function can_block_use_road(from, to) { @@ -695,85 +696,86 @@ function can_block_use_road(from, to) { switch (road_type(from, to)) { case 'iron-bridge': // https://boardgamegeek.com/thread/744750/20-rules-iron-bridge-question + // fallthrough case 'major': - return road_limit(from, to) < 8; + return road_limit(from, to) < 8 case 'minor': - return road_limit(from, to) < 4; + return road_limit(from, to) < 4 } } else { switch (road_type(from, to)) { case 'iron-bridge': if (game.iron_bridge) - return road_limit(from, to) < 3; + return road_limit(from, to) < 3 else - return road_limit(from, to) < 4; + return road_limit(from, to) < 4 case 'major': - return road_limit(from, to) < 4; + return road_limit(from, to) < 4 case 'minor': - return road_limit(from, to) < 2; + return road_limit(from, to) < 2 } } - return false; + return false } function can_block_land_move_to(who, from, to) { if (can_block_use_road(from, to)) { if (count_pinning(from) > 0) if (road_was_last_used_by_enemy(from, to)) - return false; + return false // cannot start or reinforce battles in winter if (is_winter() && is_enemy_occupied_town(to)) { // but can move through friendly sieges if (!is_friendly_field(to)) - return false; + return false if (game.distance + 1 >= block_move(who)) - return false; + return false } - return true; + return true } - return false; + return false } function can_germans_move(who) { - let from = game.location[who]; + let from = game.location[who] if (from === GERMANIA) { if (can_activate(who)) { for (let to of GERMAN_ROADS) if (can_germans_move_to(who, to)) - return true; + return true } } - return false; + return false } function can_germans_move_to(who, to) { if (are_crusaders_not_in_pool(GERMAN_CRUSADERS)) { if (is_winter() && is_enemy_occupied_town(to)) - return false; + return false if (to === ALEPPO) - return true; + return true if (to === ANTIOCH) - return true; + return true if (to === ST_SIMEON) - return road_limit(GERMANIA, ST_SIMEON) < 2; + return road_limit(GERMANIA, ST_SIMEON) < 2 } - return false; + return false } function can_block_land_move(who) { if (can_activate(who)) { - let from = game.location[who]; + let from = game.location[who] if (from) { if (is_pinned(who, from)) - return false; + return false for (let to of TOWNS[from].exits) if (can_block_land_move_to(who, from, to)) - return true; + return true } } - return false; + return false } function can_use_richards_sea_legs(who, to) { @@ -782,28 +784,28 @@ function can_use_richards_sea_legs(who, to) { if (is_english_crusader(who)) { if (is_enemy_or_contested_field(to)) { if (!game.attacker[to]) - return true; + return true if (game.attacker[to] === FRANKS) - return (game.main_road[to] === "England"); + return (game.main_road[to] === "England") } } - return false; + return false } function can_enter_besieged_port(where) { // Tripoli and Tyre are friendly to besieged defender! if (where === TRIPOLI || where === TYRE) if (besieged_player(where) === game.active) - return count_blocks_in_castle(where) < castle_limit(where); - return false; + return count_blocks_in_castle(where) < castle_limit(where) + return false } function can_leave_besieged_port(where) { // Tripoli and Tyre are friendly to besieged defender! if (where === TRIPOLI || where === TYRE) if (besieged_player(where) === game.active) - return true; - return false; + return true + return false } function can_block_sea_move_to(who, to) { @@ -811,266 +813,266 @@ function can_block_sea_move_to(who, to) { // cannot start or reinforce battles in winter if (!is_winter()) { if (can_use_richards_sea_legs(who, to)) - return true; + return true if (can_enter_besieged_port(to)) - return true; + return true } - return is_friendly_port(to); + return is_friendly_port(to) } - return false; + return false } function can_block_sea_move_from(who, from) { if (is_friendly_port(from)) - return true; + return true if (can_leave_besieged_port(from)) - return true; + return true if (from === ENGLAND) - return are_crusaders_not_in_pool(ENGLISH_CRUSADERS); + return are_crusaders_not_in_pool(ENGLISH_CRUSADERS) if (from === FRANCE) - return are_crusaders_not_in_pool(FRENCH_CRUSADERS); - return false; + return are_crusaders_not_in_pool(FRENCH_CRUSADERS) + return false } function can_block_sea_move(who) { if (can_activate_for_sea_move(who)) { - let from = game.location[who]; + let from = game.location[who] if (can_block_sea_move_from(who, from)) { for (let to of PORTS) if (to !== from && can_block_sea_move_to(who, to)) - return true; + return true } } - return false; + return false } function can_block_continue(who, from, to) { if (is_contested_field(to)) - return false; + return false if (game.distance >= block_move(who)) - return false; - return true; + return false + return true } function can_block_retreat_to(who, to) { - let from = game.location[who]; + let from = game.location[who] if (block_owner(who) === game.attacker[from]) { if (!road_was_last_used_by_friendly(from, to)) - return false; + return false } if (is_friendly_field(to) || is_vacant_town(to)) { if (can_block_use_road(from, to)) { if (road_was_last_used_by_enemy(from, to)) - return false; - return true; + return false + return true } } - return false; + return false } function can_block_retreat(who) { if (block_owner(who) === game.active) { - let from = game.location[who]; + let from = game.location[who] for (let to of TOWNS[from].exits) if (can_block_retreat_to(who, to)) - return true; + return true } - return false; + return false } function can_block_regroup_to(who, to) { // regroup during winter campaign if (is_winter() && is_enemy_occupied_town(to)) - return false; + return false if (is_friendly_field(to) || is_vacant_town(to)) { - let from = game.location[who]; + let from = game.location[who] if (can_block_use_road(from, to)) - return true; + return true } - return false; + return false } function can_block_regroup(who) { if (block_owner(who) === game.active) { - let from = game.location[who]; + let from = game.location[who] for (let to of TOWNS[from].exits) if (can_block_regroup_to(who, to)) - return true; + return true } - return false; + return false } function can_block_use_road_to_muster(from, to) { - return can_block_use_road(from, to) && is_friendly_or_vacant_field(to); + return can_block_use_road(from, to) && is_friendly_or_vacant_field(to) } function can_block_muster_with_3_moves(n0, muster) { for (let n1 of TOWNS[n0].exits) { if (can_block_use_road_to_muster(n0, n1)) { if (n1 === muster) - return true; + return true for (let n2 of TOWNS[n1].exits) { - if (n2 === n0) continue; // don't backtrack! + if (n2 === n0) continue // don't backtrack! if (can_block_use_road_to_muster(n1, n2)) { if (n2 === muster) - return true; + return true if (TOWNS[n2].exits.includes(muster)) if (can_block_use_road_to_muster(n2, muster)) - return true; + return true } } } } - return false; + return false } function can_block_muster_with_2_moves(n0, muster, avoid) { for (let n1 of TOWNS[n0].exits) { if (n1 === avoid) - continue; + continue if (can_block_use_road_to_muster(n0, n1)) { if (n1 === muster) - return true; + return true if (TOWNS[n1].exits.includes(muster)) if (can_block_use_road_to_muster(n1, muster)) - return true; + return true } } - return false; + return false } function can_block_muster_with_1_move(n0, muster) { if (TOWNS[n0].exits.includes(muster)) - return can_block_use_road_to_muster(n0, muster); - return false; + return can_block_use_road_to_muster(n0, muster) + return false } function can_block_muster(who, muster) { - let from = game.location[who]; + let from = game.location[who] if (from === muster) - return false; + return false if (can_activate(who)) { if (is_pinned(who, from)) - return false; + return false if (block_move(who) === 3) - return can_block_muster_with_3_moves(from, muster); + return can_block_muster_with_3_moves(from, muster) else - return can_block_muster_with_2_moves(from, muster, null); + return can_block_muster_with_2_moves(from, muster, null) } - return false; + return false } function can_muster_to(muster) { for (let b of BLOCKLIST) if (can_block_muster(b, muster)) - return true; - return false; + return true + return false } function can_muster_anywhere() { for (let where of TOWNLIST) if (is_friendly_field(where)) if (can_muster_to(where)) - return true; - return false; + return true + return false } function lift_siege(where) { if (is_under_siege(where) && !is_contested_town(where)) { - log("Siege lifted in " + where + "."); + log("Siege lifted in " + where + ".") for (let b of BLOCKLIST) if (is_block_in_castle_in(b, where)) - remove_from_array(game.castle, b); + remove_from_array(game.castle, b) } } function lift_all_sieges() { for (let t of TOWNLIST) - lift_siege(t); + lift_siege(t) } function reset_blocks() { for (let b of BLOCKLIST) { - game.location[b] = null; - game.steps[b] = block_max_steps(b); + game.location[b] = ELIMINATED + game.steps[b] = block_max_steps(b) } } function deploy(who, where) { - game.location[who] = where; - game.steps[who] = block_max_steps(who); + game.location[who] = where + game.steps[who] = block_max_steps(who) } function disband(who) { - game.summary.push([game.location[who]]); + game.summary.push([game.location[who]]) if (is_saladin_family(who) || block_type(who) === 'crusaders' || block_type(who) === 'military_orders') - game.location[who] = null; // permanently eliminated + game.location[who] = ELIMINATED // permanently eliminated else - game.location[who] = DEAD; // into to the pool next year - game.steps[who] = block_max_steps(who); + game.location[who] = DEAD // into to the pool next year + game.steps[who] = block_max_steps(who) } function eliminate_block(who) { - remove_from_array(game.castle, who); - if (game.sallying) remove_from_array(game.sallying, who); - if (game.storming) remove_from_array(game.storming, who); - log(block_name(who) + " was eliminated."); + remove_from_array(game.castle, who) + if (game.sallying) remove_from_array(game.sallying, who) + if (game.storming) remove_from_array(game.storming, who) + log(block_name(who) + " was eliminated.") if (is_saladin_family(who) || block_type(who) === 'crusaders' || block_type(who) === 'military_orders') - game.location[who] = null; // permanently eliminated + game.location[who] = ELIMINATED // permanently eliminated else - game.location[who] = DEAD; // into to the pool next year - game.steps[who] = block_max_steps(who); + game.location[who] = DEAD // into to the pool next year + game.steps[who] = block_max_steps(who) } function reduce_block(who) { if (game.steps[who] === 1) { - eliminate_block(who); + eliminate_block(who) } else { - --game.steps[who]; + --game.steps[who] } } // DEPLOYMENT function is_valid_frank_deployment() { - let errors = []; + let errors = [] for (let town of TOWNLIST) if (!is_within_castle_limit(town)) - errors.push(town); - return errors; + errors.push(town) + return errors } function goto_frank_deployment() { - game.active = FRANKS; - game.state = 'frank_deployment'; + game.active = FRANKS + game.state = 'frank_deployment' } states.frank_deployment = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Deployment: Waiting for " + game.active + "."; - gen_action_undo(view); - let errors = is_valid_frank_deployment(); + return view.prompt = "Deployment: Waiting for " + game.active + "." + gen_action_undo(view) + let errors = is_valid_frank_deployment() if (errors.length === 0) - gen_action(view, 'next'); + gen_action(view, 'next') for (let b of BLOCKLIST) { if (block_owner(b) === game.active && is_block_on_land(b)) if (list_seats(b).length > 1) - gen_action(view, 'block', b); + gen_action(view, 'block', b) } if (errors.length > 0) - view.prompt = "Deployment: Too many blocks in " + join(errors, "and") + "."; + view.prompt = "Deployment: Too many blocks in " + join(errors, "and") + "." else - view.prompt = "Deployment: You may make seat adjustments."; + view.prompt = "Deployment: You may make seat adjustments." }, block: function (who) { - push_undo(); - game.who = who; - game.state = 'frank_deployment_to'; + push_undo() + game.who = who + game.state = 'frank_deployment_to' }, next: function () { - clear_undo(); - goto_saracen_deployment(); + clear_undo() + goto_saracen_deployment() }, undo: pop_undo } @@ -1078,19 +1080,19 @@ states.frank_deployment = { states.frank_deployment_to = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Deployment: Waiting for " + game.active + "."; - view.prompt = "Deployment: Move " + game.who + " to " + join(list_seats(game.who), "or") + "."; - gen_action_undo(view); - gen_action(view, 'block', game.who); - let from = game.location[game.who]; + return view.prompt = "Deployment: Waiting for " + game.active + "." + view.prompt = "Deployment: Move " + game.who + " to " + join(list_seats(game.who), "or") + "." + gen_action_undo(view) + gen_action(view, 'block', game.who) + let from = game.location[game.who] for (let town of list_seats(game.who)) if (town !== from) - gen_action(view, 'town', town); + gen_action(view, 'town', town) }, town: function (where) { - game.location[game.who] = where; - game.who = null; - game.state = 'frank_deployment'; + game.location[game.who] = where + game.who = null + game.state = 'frank_deployment' }, block: pop_undo, undo: pop_undo @@ -1098,39 +1100,39 @@ states.frank_deployment_to = { function goto_saracen_deployment() { for (let i = 0; i < 4; ++i) { - let nomad = select_random_block(S_POOL); - log(BLOCKS[nomad].name + " arrived in " + block_home(nomad) + "."); - deploy(nomad, block_home(nomad)); + let nomad = select_random_block(S_POOL) + log(BLOCKS[nomad].name + " arrived in " + block_home(nomad) + ".") + deploy(nomad, block_home(nomad)) } - game.active = SARACENS; - game.state = 'saracen_deployment'; - game.who = SALADIN; + game.active = SARACENS + game.state = 'saracen_deployment' + game.who = SALADIN } states.saracen_deployment = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Deployment: Waiting for " + game.active + "."; - view.prompt = "Deployment: You may swap places with Saladin and any other block of his family."; - gen_action(view, 'next'); - gen_action_undo(view); + return view.prompt = "Deployment: Waiting for " + game.active + "." + view.prompt = "Deployment: You may swap places with Saladin and any other block of his family." + gen_action(view, 'next') + gen_action_undo(view) if (game.location[SALADIN] === DAMASCUS) { for (let b of SALADIN_FAMILY) if (b !== SALADIN && game.location[b] !== game.location[SALADIN]) - gen_action(view, 'block', b); + gen_action(view, 'block', b) } }, block: function (who) { - push_undo(); - let saladin = game.location[SALADIN]; - game.location[SALADIN] = game.location[who]; - game.location[who] = saladin; - game.who = null; + push_undo() + let saladin = game.location[SALADIN] + game.location[SALADIN] = game.location[who] + game.location[who] = saladin + game.who = null }, next: function () { - clear_undo(); - game.who = null; - start_year(); + clear_undo() + game.who = null + start_year() }, undo: pop_undo } @@ -1138,235 +1140,235 @@ states.saracen_deployment = { // GAME TURN function is_friendly_town_for_player(p, where) { - return (count_player(enemy(p), where) === 0) && (count_player(p, where) > 0 || is_player_kingdom(p, where)); + return (count_player(enemy(p), where) === 0) && (count_player(p, where) > 0 || is_player_kingdom(p, where)) } function is_friendly_town_for_vp(p, town) { if (is_friendly_town_for_player(p, town)) - return true; + return true if (is_under_siege(town)) - return besieged_player(town) === p; - return false; + return besieged_player(town) === p + return false } function count_victory_points(p) { - let vp = 0; + let vp = 0 for (let town of VICTORY_TOWNS) if (is_friendly_town_for_vp(p, town)) - ++ vp; - return vp; + ++ vp + return vp } function check_sudden_death() { if (count_victory_points(FRANKS) === 7) { - game.state = 'game_over'; - game.result = FRANKS; + game.state = 'game_over' + game.result = FRANKS game.victory = "Franks controlled all seven victory cities." - log(""); - log(game.victory); - return true; + log("") + log(game.victory) + return true } if (count_victory_points(SARACENS) === 7) { - game.state = 'game_over'; - game.result = SARACENS; + game.state = 'game_over' + game.result = SARACENS game.victory = "Saracens controlled all seven victory cities." - log(""); - log(game.victory); - return true; + log("") + log(game.victory) + return true } } function start_year() { - log(""); - log("Start Year " + game.year); + log("") + log("Start Year " + game.year) - game.turn = 1; + game.turn = 1 - let deck = shuffle_deck(); - game.f_hand = deal_cards(deck, 6); - game.s_hand = deal_cards(deck, 6); - game.prior_f_card = 0; - game.prior_s_card = 0; + let deck = shuffle_deck() + game.f_hand = deal_cards(deck, 6) + game.s_hand = deal_cards(deck, 6) + game.prior_f_card = 0 + game.prior_s_card = 0 - start_game_turn(); + start_game_turn() } function start_game_turn() { - log(""); - log("Start Turn " + game.turn + " of Year " + game.year); + log("") + log("Start Turn " + game.turn + " of Year " + game.year) - game.guide = null; - game.jihad = null; + game.guide = null + game.jihad = null // Reset movement and attack tracking state - reset_road_limits(); - game.last_used = {}; - game.attacker = {}; - game.reserves1 = []; - game.reserves2 = []; - game.moved = {}; + reset_road_limits() + game.last_used = {} + game.attacker = {} + game.reserves1 = [] + game.reserves2 = [] + game.moved = {} - goto_card_phase(); + goto_card_phase() } // CARD PHASE function goto_card_phase() { - game.f_card = 0; - game.s_card = 0; - game.show_cards = false; - game.state = 'play_card'; - game.active = BOTH; + game.f_card = 0 + game.s_card = 0 + game.show_cards = false + game.state = 'play_card' + game.active = BOTH } function resume_play_card() { if (game.s_card && game.f_card) - reveal_cards(); + reveal_cards() else if (game.f_card) - game.active = SARACENS; + game.active = SARACENS else if (game.s_card) - game.active = FRANKS; + game.active = FRANKS else - game.active = BOTH; + game.active = BOTH } states.play_card = { prompt: function (view, current) { if (current === OBSERVER) { - view.prior_s_card = game.prior_s_card; - view.prior_f_card = game.prior_f_card; - return view.prompt = "Card Phase: Waiting for players to play a card."; + view.prior_s_card = game.prior_s_card + view.prior_f_card = game.prior_f_card + return view.prompt = "Card Phase: Waiting for players to play a card." } if (current === FRANKS) { - view.prior_s_card = game.prior_s_card; + view.prior_s_card = game.prior_s_card if (game.f_card) { - view.prompt = "Card Phase: Waiting for Saracens to play a card."; - gen_action(view, 'undo'); + view.prompt = "Card Phase: Waiting for Saracens to play a card." + gen_action(view, 'undo') } else { - view.prior_f_card = game.prior_f_card; - view.prompt = "Card Phase: Play a card."; + view.prior_f_card = game.prior_f_card + view.prompt = "Card Phase: Play a card." for (let c of game.f_hand) if (game.turn > 1 || c !== INTRIGUE) - gen_action(view, 'play', c); + gen_action(view, 'play', c) } } if (current === SARACENS) { - view.prior_f_card = game.prior_f_card; + view.prior_f_card = game.prior_f_card if (game.s_card) { - view.prompt = "Card Phase: Waiting for Franks to play a card."; - gen_action(view, 'undo'); + view.prompt = "Card Phase: Waiting for Franks to play a card." + gen_action(view, 'undo') } else { - view.prior_s_card = game.prior_s_card; - view.prompt = "Card Phase: Play a card."; + view.prior_s_card = game.prior_s_card + view.prompt = "Card Phase: Play a card." for (let c of game.s_hand) if (game.turn > 1 || c !== INTRIGUE) - gen_action(view, 'play', c); + gen_action(view, 'play', c) } } }, play: function (card, current) { if (current === FRANKS) { - remove_from_array(game.f_hand, card); - game.f_card = card; + remove_from_array(game.f_hand, card) + game.f_card = card } if (current === SARACENS) { - remove_from_array(game.s_hand, card); - game.s_card = card; + remove_from_array(game.s_hand, card) + game.s_card = card } - resume_play_card(); + resume_play_card() }, undo: function (_, current) { if (current === FRANKS) { - game.f_hand.push(game.f_card); - game.f_card = 0; + game.f_hand.push(game.f_card) + game.f_card = 0 } if (current === SARACENS) { - game.s_hand.push(game.s_card); - game.s_card = 0; + game.s_hand.push(game.s_card) + game.s_card = 0 } - resume_play_card(); + resume_play_card() } } function reveal_cards() { - log(""); - log("Franks played " + CARDS[game.f_card].name + "."); - log("Saracens played " + CARDS[game.s_card].name + "."); - game.show_cards = true; + log("") + log("Franks played " + CARDS[game.f_card].name + ".") + log("Saracens played " + CARDS[game.s_card].name + ".") + game.show_cards = true if (CARDS[game.f_card].event && CARDS[game.s_card].event) { - log("Game Turn cancelled."); - game.prior_f_card = game.f_card; - game.prior_s_card = game.s_card; - end_game_turn(); - return; + log("Game Turn cancelled.") + game.prior_f_card = game.f_card + game.prior_s_card = game.s_card + end_game_turn() + return } if (game.f_card === INTRIGUE) { - game.f_card = game.prior_s_card; - log("Intrigue copied " + CARDS[game.f_card].name + "."); + game.f_card = game.prior_s_card + log("Intrigue copied " + CARDS[game.f_card].name + ".") } if (game.s_card === INTRIGUE) { - game.s_card = game.prior_f_card; - log("Intrigue copied " + CARDS[game.s_card].name + "."); + game.s_card = game.prior_f_card + log("Intrigue copied " + CARDS[game.s_card].name + ".") } - delete game.winter_campaign; + delete game.winter_campaign if (is_winter()) { if (game.f_card === WINTER_CAMPAIGN) - game.winter_campaign = FRANKS; + game.winter_campaign = FRANKS if (game.s_card === WINTER_CAMPAIGN) - game.winter_campaign = SARACENS; + game.winter_campaign = SARACENS } - game.prior_f_card = game.f_card; - game.prior_s_card = game.s_card; + game.prior_f_card = game.f_card + game.prior_s_card = game.s_card - let fp = CARDS[game.f_card].event ? 10 : CARDS[game.f_card].moves; - let sp = CARDS[game.s_card].event ? 10 : CARDS[game.s_card].moves; + let fp = CARDS[game.f_card].event ? 10 : CARDS[game.f_card].moves + let sp = CARDS[game.s_card].event ? 10 : CARDS[game.s_card].moves if (fp === sp) { - let die = roll_d6(); - log("Random first player."); + let die = roll_d6() + log("Random first player.") if (die > 3) - ++fp; + ++fp else - ++sp; + ++sp } if (fp > sp) { - game.p1 = FRANKS; - game.p2 = SARACENS; + game.p1 = FRANKS + game.p2 = SARACENS } else { - game.p1 = SARACENS; - game.p2 = FRANKS; + game.p1 = SARACENS + game.p2 = FRANKS } - game.active = game.p1; - start_player_turn(); + game.active = game.p1 + start_player_turn() } function start_player_turn() { - log(""); - log("Start " + game.active); - reset_road_limits(); - game.main_road = {}; - let card = CARDS[game.active === FRANKS ? game.f_card : game.s_card]; + log("") + log("Start " + game.active) + reset_road_limits() + game.main_road = {} + let card = CARDS[game.active === FRANKS ? game.f_card : game.s_card] if (card.event) - goto_event_card(card.event); + goto_event_card(card.event) else - goto_move_phase(card.moves); + goto_move_phase(card.moves) } function end_player_turn() { - game.moves = 0; - game.main_road = null; + game.moves = 0 + game.main_road = null if (game.active === game.p2) { - goto_combat_phase(); + goto_combat_phase() } else { - game.active = game.p2; - start_player_turn(); + game.active = game.p2 + start_player_turn() } } @@ -1374,66 +1376,66 @@ function end_player_turn() { function goto_event_card(event) { switch (event) { - case 'assassins': goto_assassins(); break; - case 'guide': goto_guide(); break; - case 'jihad': goto_jihad(); break; - case 'manna': goto_manna(); break; + case 'assassins': goto_assassins(); break + case 'guide': goto_guide(); break + case 'jihad': goto_jihad(); break + case 'manna': goto_manna(); break } } function goto_assassins() { - game.state = 'assassins'; - game.who = ASSASSINS; + game.state = 'assassins' + game.who = ASSASSINS } states.assassins = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Assassins: Waiting for " + game.active + "."; - view.prompt = "Assassins: Choose one enemy block."; + return view.prompt = "Assassins: Waiting for " + game.active + "." + view.prompt = "Assassins: Choose one enemy block." for (let b of BLOCKLIST) { if (is_block_on_land(b) && block_owner(b) === enemy(game.active)) - gen_action(view, 'block', b); + gen_action(view, 'block', b) } }, block: function (who) { - game.where = game.location[who]; - game.who = select_random_enemy_block(game.where); - game.location[ASSASSINS] = game.where; - game.state = 'assassins_show_1'; + game.where = game.location[who] + game.who = select_random_enemy_block(game.where) + game.location[ASSASSINS] = game.where + game.state = 'assassins_show_1' }, } states.assassins_show_1 = { prompt: function (view, current) { - view.assassinate = game.who; - view.who = ASSASSINS; + view.assassinate = game.who + view.who = ASSASSINS if (is_inactive_player(current)) - return view.prompt = "Assassins: Waiting for " + game.active + "."; - view.prompt = "Assassins: The assassins target " + block_name(game.who) + " in " + game.where + "."; - gen_action(view, 'next'); - gen_action(view, 'block', game.who); - gen_action(view, 'block', ASSASSINS); + return view.prompt = "Assassins: Waiting for " + game.active + "." + view.prompt = "Assassins: The assassins target " + block_name(game.who) + " in " + game.where + "." + gen_action(view, 'next') + gen_action(view, 'block', game.who) + gen_action(view, 'block', ASSASSINS) }, next: assassins_next_1, block: assassins_next_1, } function assassins_next_1() { - assassinate(game.who, game.where); - game.state = 'assassins_show_2'; + assassinate(game.who, game.where) + game.state = 'assassins_show_2' } states.assassins_show_2 = { prompt: function (view, current) { - view.assassinate = game.who; - view.who = ASSASSINS; + view.assassinate = game.who + view.who = ASSASSINS if (is_inactive_player(current)) - return view.prompt = "Assassins: Waiting for " + game.active + "."; - view.prompt = "Assassins: The assassins hit " + block_name(game.who) + " in " + game.where + "."; - gen_action(view, 'next'); - gen_action(view, 'block', ASSASSINS); - gen_action(view, 'town', MASYAF); + return view.prompt = "Assassins: Waiting for " + game.active + "." + view.prompt = "Assassins: The assassins hit " + block_name(game.who) + " in " + game.where + "." + gen_action(view, 'next') + gen_action(view, 'block', ASSASSINS) + gen_action(view, 'town', MASYAF) }, next: assassins_next_2, block: assassins_next_2, @@ -1441,111 +1443,111 @@ states.assassins_show_2 = { } function assassins_next_2() { - lift_siege(game.where); - game.location[ASSASSINS] = MASYAF; - game.who = null; - game.where = null; - end_player_turn(); + lift_siege(game.where) + game.location[ASSASSINS] = MASYAF + game.who = null + game.where = null + end_player_turn() } function assassinate(who, where) { - let hits = 0; - let rolls = []; + let hits = 0 + let rolls = [] for (let i = 0; i < 3; ++i) { - let die = roll_d6(); + let die = roll_d6() if (die <= 3) { - rolls.push(DIE_HIT[die]); - ++hits; + rolls.push(DIE_HIT[die]) + ++hits } else { - rolls.push(DIE_MISS[die]); + rolls.push(DIE_MISS[die]) } } - hits = Math.min(hits, game.steps[who]); - log("Assassins hit " + block_name(who) + " in " + where + ": " + rolls.join("") + "."); + hits = Math.min(hits, game.steps[who]) + log("Assassins hit " + block_name(who) + " in " + where + ": " + rolls.join("") + ".") for (let i = 0; i < hits; ++i) - reduce_block(who); + reduce_block(who) } function goto_guide() { - game.guide = game.active; - game.state = 'move_phase_event'; - game.summary = []; + game.guide = game.active + game.state = 'move_phase_event' + game.summary = [] } function goto_jihad() { - game.jihad = game.active; - game.state = 'move_phase_event'; - game.summary = []; + game.jihad = game.active + game.state = 'move_phase_event' + game.summary = [] } function goto_select_jihad() { - game.jihad_list = []; + game.jihad_list = [] for (let where of TOWNLIST) if (is_contested_field(where) || besieging_player(where) === game.active) - game.jihad_list.push(where); + game.jihad_list.push(where) if (game.jihad_list.length === 0) { - delete game.jihad_list; - return end_player_turn(); + delete game.jihad_list + return end_player_turn() } if (game.jihad_list.length === 1) { - game.jihad = game.jihad_list[0]; - log("Jihad in " + game.jihad + "."); - delete game.jihad_list; - return end_player_turn(); + game.jihad = game.jihad_list[0] + log("Jihad in " + game.jihad + ".") + delete game.jihad_list + return end_player_turn() } - game.state = 'select_jihad'; + game.state = 'select_jihad' } states.select_jihad = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Jihad: Waiting for " + game.active + "."; - view.prompt = "Jihad: Select battle for Jihad."; + return view.prompt = "Jihad: Waiting for " + game.active + "." + view.prompt = "Jihad: Select battle for Jihad." for (let town of game.jihad_list) - gen_action(view, 'town', town); + gen_action(view, 'town', town) }, town: function (where) { - game.jihad = where; - log("Jihad in " + game.jihad + "."); - delete game.jihad_list; - end_player_turn(); + game.jihad = where + log("Jihad in " + game.jihad + ".") + delete game.jihad_list + end_player_turn() }, } function goto_manna() { - game.state = 'manna'; - game.moves = 3; - game.moved = {}; - game.summary = []; + game.state = 'manna' + game.moves = 3 + game.moved = {} + game.summary = [] } states.manna = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Manna: Waiting for " + game.active + "."; - view.prompt = "Manna: Add one step to three different friendly blocks \u2014 " + game.moves + " left."; - gen_action_undo(view); - gen_action(view, 'next'); + return view.prompt = "Manna: Waiting for " + game.active + "." + view.prompt = "Manna: Add one step to three different friendly blocks \u2014 " + game.moves + " left." + gen_action_undo(view) + gen_action(view, 'next') if (game.moves > 0) { for (let b of BLOCKLIST) { if (is_block_on_land(b) && block_owner(b) === game.active && !game.moved[b]) if (game.steps[b] < block_max_steps(b)) - gen_action(view, 'block', b); + gen_action(view, 'block', b) } } }, block: function (who) { - push_undo(); - game.summary.push([game.location[who]]); - ++game.steps[who]; - --game.moves; - game.moved[who] = 1; + push_undo() + game.summary.push([game.location[who]]) + ++game.steps[who] + --game.moves + game.moved[who] = 1 }, next: function () { - clear_undo(); - print_summary(game.active + " used Manna:"); - game.moved = {}; - end_player_turn(); + clear_undo() + print_summary(game.active + " used Manna:") + game.moved = {} + end_player_turn() }, undo: pop_undo } @@ -1554,102 +1556,102 @@ states.manna = { function queue_attack(who, round) { if (round === 1) - return ATTACK_MARK; + return ATTACK_MARK if (round === 2) { - game.reserves1.push(who); - return RESERVE_MARK_1; + game.reserves1.push(who) + return RESERVE_MARK_1 } if (round === 3) { - game.reserves2.push(who); - return RESERVE_MARK_2; + game.reserves2.push(who) + return RESERVE_MARK_2 } } function move_block(who, from, to) { - game.location[who] = to; - game.road_limit[road_id(from, to)] = road_limit(from, to) + 1; - game.distance ++; + game.location[who] = to + game.road_limit[road_id(from, to)] = road_limit(from, to) + 1 + game.distance ++ if (is_contested_field(to)) { - game.last_used[road_id(from, to)] = game.active; + game.last_used[road_id(from, to)] = game.active // 6.56 Main Attack relief force by Player 2 arrives one round later than normal - let relief_delay = 0; + let relief_delay = 0 if (game.active === game.p2 && besieged_player(to) === game.p2) { - relief_delay = 1; + relief_delay = 1 } if (!game.attacker[to]) { - game.attacker[to] = game.active; - game.main_road[to] = from; - return queue_attack(who, 1 + relief_delay); + game.attacker[to] = game.active + game.main_road[to] = from + return queue_attack(who, 1 + relief_delay) } else { // Attacker main attack or reinforcements if (game.attacker[to] === game.active) { if (game.main_road[to] !== from) - return queue_attack(who, 2 + relief_delay); - return queue_attack(who, 1 + relief_delay); + return queue_attack(who, 2 + relief_delay) + return queue_attack(who, 1 + relief_delay) } // Defender reinforcements if (!game.main_road[to]) - game.main_road[to] = from; + game.main_road[to] = from if (game.main_road[to] === from) { - return queue_attack(who, 2); + return queue_attack(who, 2) } else { - return queue_attack(who, 3); + return queue_attack(who, 3) } } } - return false; + return false } function goto_move_phase(moves) { - game.state = 'move_phase'; - game.moves = moves; + game.state = 'move_phase' + game.moves = moves } function end_move_phase() { if (game.moves > 0) { - push_undo(); - game.state = 'confirm_end_move_phase'; - return; + push_undo() + game.state = 'confirm_end_move_phase' + return } - clear_undo(); - game.who = null; - game.where = null; - game.moves = 0; + clear_undo() + game.who = null + game.where = null + game.moves = 0 // declined to use winter campaign if (game.winter_campaign === game.active) - delete game.winter_campaign; + delete game.winter_campaign if (game.active === game.jihad) - goto_select_jihad(); + goto_select_jihad() else - end_player_turn(); + end_player_turn() } states.confirm_end_move_phase = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; + return view.prompt = "Move Phase: Waiting for " + game.active + "." if (game.moves > 1) - view.prompt = "Move Phase: You have " + game.moves + " moves left"; + view.prompt = "Move Phase: You have " + game.moves + " moves left" else - view.prompt = "Move Phase: You have 1 move left"; - view.prompt += " \u2014 are you sure you want to end the move phase?"; - gen_action_undo(view); - gen_action(view, 'end_move_phase'); + view.prompt = "Move Phase: You have 1 move left" + view.prompt += " \u2014 are you sure you want to end the move phase?" + gen_action_undo(view) + gen_action(view, 'end_move_phase') }, end_move_phase: function () { if (game.moves === 1) - log(game.active + " did nothing with " + game.moves + " move."); + log(game.active + " did nothing with " + game.moves + " move.") else - log(game.active + " did nothing with " + game.moves + " moves."); - game.moves = 0; - end_move_phase(); + log(game.active + " did nothing with " + game.moves + " moves.") + game.moves = 0 + end_move_phase() }, undo: pop_undo } @@ -1657,51 +1659,51 @@ states.confirm_end_move_phase = { states.move_phase = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; + return view.prompt = "Move Phase: Waiting for " + game.active + "." if (game.moves === 0) - view.prompt = "Move Phase: No moves left."; + view.prompt = "Move Phase: No moves left." else if (game.moves === 1) - view.prompt = "Move Phase: 1 move left."; + view.prompt = "Move Phase: 1 move left." else - view.prompt = "Move Phase: " + game.moves + " moves left."; - gen_action_undo(view); - gen_action(view, 'end_move_phase'); + view.prompt = "Move Phase: " + game.moves + " moves left." + gen_action_undo(view) + gen_action(view, 'end_move_phase') if (game.moves > 0) { for (let b of BLOCKLIST) { if (can_block_land_move(b)) - gen_action(view, 'block', b); + gen_action(view, 'block', b) if (can_block_sea_move(b)) - gen_action(view, 'block', b); + gen_action(view, 'block', b) if (can_germans_move(b)) - gen_action(view, 'block', b); + gen_action(view, 'block', b) } if (can_muster_anywhere()) - gen_action(view, 'muster'); + gen_action(view, 'muster') if (game.winter_campaign === game.active) - gen_action(view, 'winter_campaign'); + gen_action(view, 'winter_campaign') } }, winter_campaign: function () { - push_undo(); - --game.moves; - game.state = 'winter_campaign'; + push_undo() + --game.moves + game.state = 'winter_campaign' }, muster: function () { - push_undo(); - --game.moves; - game.state = 'muster'; + push_undo() + --game.moves + game.state = 'muster' }, block: function (who) { - push_undo(); - game.summary = []; - game.who = who; - game.where = game.location[who]; + push_undo() + game.summary = [] + game.who = who + game.where = game.location[who] if (game.where === GERMANIA) { - game.state = 'german_move_to'; + game.state = 'german_move_to' } else if (game.where === FRANCE || game.where === ENGLAND) { - game.state = 'sea_move_to'; + game.state = 'sea_move_to' } else { - game.state = 'move_phase_to'; + game.state = 'move_phase_to' } }, end_move_phase: end_move_phase, @@ -1711,21 +1713,21 @@ states.move_phase = { states.move_phase_event = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = group_move_name(1) + "Waiting for " + game.active + "."; - view.prompt = group_move_name(0) + "Choose a block to group move."; - gen_action_undo(view); - gen_action(view, 'end_move_phase'); + return view.prompt = group_move_name(1) + "Waiting for " + game.active + "." + view.prompt = group_move_name(0) + "Choose a block to group move." + gen_action_undo(view) + gen_action(view, 'end_move_phase') for (let b of BLOCKLIST) if (can_block_land_move(b)) - gen_action(view, 'block', b); + gen_action(view, 'block', b) }, block: function (who) { - push_undo(); - game.where = game.location[who]; - game.who = who; - game.distance = 0; - game.last_from = null; - game.state = 'group_move_to'; + push_undo() + game.where = game.location[who] + game.who = who + game.distance = 0 + game.last_from = null + game.state = 'group_move_to' }, end_move_phase: end_move_phase, undo: pop_undo @@ -1735,55 +1737,55 @@ states.move_phase_event = { states.move_phase_to = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; - view.prompt = "Move Phase: Move " + block_name(game.who); - gen_action_undo(view); - gen_action(view, 'block', game.who); - let from = game.location[game.who]; - let can_group_move = false; - let can_sea_move = false; + return view.prompt = "Move Phase: Waiting for " + game.active + "." + view.prompt = "Move Phase: Move " + block_name(game.who) + gen_action_undo(view) + gen_action(view, 'block', game.who) + let from = game.location[game.who] + let can_group_move = false + let can_sea_move = false if (can_block_land_move(game.who)) { for (let to of TOWNS[from].exits) { if (can_block_land_move_to(game.who, from, to)) { - gen_action(view, 'town', to); - can_group_move = true; + gen_action(view, 'town', to) + can_group_move = true } } } if (can_block_sea_move(game.who)) { - gen_action(view, 'town', SEA); - can_sea_move = true; + gen_action(view, 'town', SEA) + can_sea_move = true } if (can_group_move && can_sea_move) - view.prompt += " by road or by sea."; + view.prompt += " by road or by sea." else if (can_sea_move) - view.prompt += " by sea."; + view.prompt += " by sea." else - view.prompt += " by road."; + view.prompt += " by road." }, town: function (to) { - let from = game.location[game.who]; + let from = game.location[game.who] if (to === SEA) { - log_move_start(from); - log_move_continue(to); - game.location[game.who] = SEA; - game.state = 'sea_move_to'; - return; - } - -- game.moves; - game.distance = 0; - log_move_start(from); - let mark = move_block(game.who, from, to); + log_move_start(from) + log_move_continue(to) + game.location[game.who] = SEA + game.state = 'sea_move_to' + return + } + -- game.moves + game.distance = 0 + log_move_start(from) + let mark = move_block(game.who, from, to) if (mark) - log_move_continue(to + mark); + log_move_continue(to + mark) else - log_move_continue(to); - lift_siege(from); - game.last_from = from; + log_move_continue(to) + lift_siege(from) + game.last_from = from if (!can_block_continue(game.who, from, to)) - end_move(); + end_move() else { - game.state = 'group_move_to'; + game.state = 'group_move_to' } }, block: pop_undo, @@ -1793,44 +1795,44 @@ states.move_phase_to = { // GROUP MOVE function group_move_name() { - if (game.active === game.jihad) return "Jihad: "; - if (game.active === game.guide) return "Guide: "; - return "Group Move: "; + if (game.active === game.jihad) return "Jihad: " + if (game.active === game.guide) return "Guide: " + return "Group Move: " } function can_group_move_more() { for (let b of BLOCKLIST) if (game.location[b] === game.where) if (can_block_land_move(b)) - return true; - return false; + return true + return false } states.group_move_who = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = group_move_name(1) + "Waiting for " + game.active + "."; - view.prompt = group_move_name(0) + "Move blocks from " + game.where + "."; - gen_action_undo(view); + return view.prompt = group_move_name(1) + "Waiting for " + game.active + "." + view.prompt = group_move_name(0) + "Move blocks from " + game.where + "." + gen_action_undo(view) if (game.active === game.guide || game.active === game.jihad) - gen_action(view, 'end_move_phase'); + gen_action(view, 'end_move_phase') else - gen_action(view, 'end_group_move'); + gen_action(view, 'end_group_move') for (let b of BLOCKLIST) if (game.location[b] === game.where) if (can_block_land_move(b)) - gen_action(view, 'block', b); + gen_action(view, 'block', b) }, block: function (who) { - push_undo(); - game.who = who; - game.distance = 0; - game.last_from = null; - game.state = 'group_move_to'; + push_undo() + game.who = who + game.distance = 0 + game.last_from = null + game.state = 'group_move_to' }, end_move_phase: function () { - end_group_move(); - end_move_phase(); + end_group_move() + end_move_phase() }, end_group_move: end_group_move, undo: pop_undo @@ -1839,40 +1841,40 @@ states.group_move_who = { states.group_move_to = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = group_move_name(1) + "Waiting for " + game.active + "."; - view.prompt = group_move_name(0) + "Move " + block_name(game.who) + "."; - gen_action_undo(view); + return view.prompt = group_move_name(1) + "Waiting for " + game.active + "." + view.prompt = group_move_name(0) + "Move " + block_name(game.who) + "." + gen_action_undo(view) if (game.distance === 0) - gen_action(view, 'block', game.who); - let from = game.location[game.who]; + gen_action(view, 'block', game.who) + let from = game.location[game.who] if (game.distance > 0) { // cannot start or reinforce battles in winter if (!(is_winter() && is_enemy_occupied_town(from))) - gen_action(view, 'town', from); + gen_action(view, 'town', from) } for (let to of TOWNS[from].exits) { if (to !== game.last_from && can_block_land_move_to(game.who, from, to)) { - gen_action(view, 'town', to); + gen_action(view, 'town', to) } } }, town: function (to) { - let from = game.location[game.who]; + let from = game.location[game.who] if (to === from) { - end_move(); - return; + end_move() + return } if (game.distance === 0) - log_move_start(from); - let mark = move_block(game.who, from, to); + log_move_start(from) + let mark = move_block(game.who, from, to) if (mark) - log_move_continue(to + mark); + log_move_continue(to + mark) else - log_move_continue(to); - lift_siege(from); - game.last_from = from; + log_move_continue(to) + lift_siege(from) + game.last_from = from if (!can_block_continue(game.who, from, to)) - end_move(); + end_move() }, block: pop_undo, undo: pop_undo @@ -1880,19 +1882,19 @@ states.group_move_to = { function end_move() { if (game.distance > 0) - game.moved[game.who] = 1; - log_move_end(); - game.who = null; - game.distance = 0; + game.moved[game.who] = 1 + log_move_end() + game.who = null + game.distance = 0 if (can_group_move_more()) - game.state = 'group_move_who'; + game.state = 'group_move_who' else - end_group_move(); + end_group_move() } function end_group_move() { - print_summary(game.active + " activated " + game.where + ":"); - game.state = 'move_phase'; + print_summary(game.active + " activated " + game.where + ":") + game.state = 'move_phase' } // SEA MOVE @@ -1900,27 +1902,27 @@ function end_group_move() { states.german_move_to = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; - view.prompt = "Move Phase: Move " + block_name(game.who) + " to Aleppo, Antioch, or St. Simeon."; - gen_action_undo(view); - gen_action(view, 'block', game.who); + return view.prompt = "Move Phase: Waiting for " + game.active + "." + view.prompt = "Move Phase: Move " + block_name(game.who) + " to Aleppo, Antioch, or St. Simeon." + gen_action_undo(view) + gen_action(view, 'block', game.who) for (let to of GERMAN_ROADS) if (can_germans_move_to(game.who, to)) - gen_action(view, 'town', to); + gen_action(view, 'town', to) }, town: function (to) { - --game.moves; - let from = GERMANIA; - game.location[game.who] = to; - game.moved[game.who] = 1; - game.distance = 0; - let mark = move_block(game.who, from, to); + --game.moves + let from = GERMANIA + game.location[game.who] = to + game.moved[game.who] = 1 + game.distance = 0 + let mark = move_block(game.who, from, to) if (mark) - log(game.active + " moved:\n Germania \u2192 " + to + mark + "."); + log(game.active + " moved:\n Germania \u2192 " + to + mark + ".") else - log(game.active + " moved:\n Germania \u2192 " + to + "."); - game.who = null; - game.state = 'move_phase'; + log(game.active + " moved:\n Germania \u2192 " + to + ".") + game.who = null + game.state = 'move_phase' }, block: pop_undo, undo: pop_undo, @@ -1929,53 +1931,53 @@ states.german_move_to = { states.sea_move_to = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; + return view.prompt = "Move Phase: Waiting for " + game.active + "." if (is_english_crusader(game.who)) - view.prompt = "Sea Move: Move " + block_name(game.who) + " to a port."; + view.prompt = "Sea Move: Move " + block_name(game.who) + " to a port." else - view.prompt = "Sea Move: Move " + block_name(game.who) + " to a friendly port."; - gen_action_undo(view); - gen_action(view, 'block', game.who); - let from = game.location[game.who]; + view.prompt = "Sea Move: Move " + block_name(game.who) + " to a friendly port." + gen_action_undo(view) + gen_action(view, 'block', game.who) + let from = game.location[game.who] if (from === GERMANIA) { for (let to of GERMAN_ROADS) if (can_germans_move_to(game.who, to)) - gen_action(view, 'town', to); + gen_action(view, 'town', to) } else { for (let to of PORTS) if (to !== game.where && can_block_sea_move_to(game.who, to)) - gen_action(view, 'town', to); + gen_action(view, 'town', to) } }, town: function (to) { - --game.moves; + --game.moves - let from = game.where; - game.location[game.who] = to; - game.moved[game.who] = 1; + let from = game.where + game.location[game.who] = to + game.moved[game.who] = 1 - lift_siege(from); + lift_siege(from) - remove_from_array(game.castle, game.who); + remove_from_array(game.castle, game.who) if (besieged_player(to) === game.active && is_more_room_in_castle(to)) { // Move into besieged fortified port - game.castle.push(game.who); - log(game.active + " sea moved:\n" + from + " \u2192 " + to + " castle."); + game.castle.push(game.who) + log(game.active + " sea moved:\n" + from + " \u2192 " + to + " castle.") } else if (!is_friendly_port(to)) { // English Crusaders attack! - game.attacker[to] = FRANKS; - game.main_road[to] = "England"; - log(game.active + " sea moved:\n" + from + " \u2192 " + to + ATTACK_MARK + "."); + game.attacker[to] = FRANKS + game.main_road[to] = "England" + log(game.active + " sea moved:\n" + from + " \u2192 " + to + ATTACK_MARK + ".") } else { // Normal move. - log(game.active + " sea moved:\n" + from + " \u2192 " + to + "."); + log(game.active + " sea moved:\n" + from + " \u2192 " + to + ".") } - game.who = null; - game.state = 'move_phase'; + game.who = null + game.state = 'move_phase' }, block: pop_undo, undo: pop_undo, @@ -1986,27 +1988,27 @@ states.sea_move_to = { states.muster = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; - view.prompt = "Muster: Choose a friendly muster town."; - gen_action_undo(view); + return view.prompt = "Move Phase: Waiting for " + game.active + "." + view.prompt = "Muster: Choose a friendly muster town." + gen_action_undo(view) for (let where of TOWNLIST) { // cannot start or reinforce battles in winter if (is_winter()) { if (is_friendly_town(where)) if (can_muster_to(where)) - gen_action(view, 'town', where); + gen_action(view, 'town', where) } else { if (is_friendly_field(where)) if (can_muster_to(where)) - gen_action(view, 'town', where); + gen_action(view, 'town', where) } } }, town: function (where) { - push_undo(); - game.where = where; - game.state = 'muster_who'; - game.summary = []; + push_undo() + game.where = where + game.state = 'muster_who' + game.summary = [] }, undo: pop_undo, } @@ -2014,24 +2016,24 @@ states.muster = { states.muster_who = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; - view.prompt = "Muster: Move blocks to " + game.where + "."; - view.muster = game.where; - gen_action_undo(view); - gen_action(view, 'end_muster'); + return view.prompt = "Move Phase: Waiting for " + game.active + "." + view.prompt = "Muster: Move blocks to " + game.where + "." + view.muster = game.where + gen_action_undo(view) + gen_action(view, 'end_muster') for (let b of BLOCKLIST) if (can_block_muster(b, game.where)) - gen_action(view, 'block', b); + gen_action(view, 'block', b) }, block: function (who) { - push_undo(); - game.who = who; - game.state = 'muster_move_1'; + push_undo() + game.who = who + game.state = 'muster_move_1' }, end_muster: function () { - print_summary(game.active + " mustered to " + game.where + ":"); - game.where = null; - game.state = 'move_phase'; + print_summary(game.active + " mustered to " + game.where + ":") + game.where = null + game.state = 'move_phase' }, undo: pop_undo, } @@ -2039,39 +2041,39 @@ states.muster_who = { states.muster_move_1 = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; - view.prompt = "Muster: Move " + block_name(game.who) + " to " + game.where + "."; - view.muster = game.where; - gen_action_undo(view); - gen_action(view, 'block', game.who); - let from = game.location[game.who]; - let muster = game.where; + return view.prompt = "Move Phase: Waiting for " + game.active + "." + view.prompt = "Muster: Move " + block_name(game.who) + " to " + game.where + "." + view.muster = game.where + gen_action_undo(view) + gen_action(view, 'block', game.who) + let from = game.location[game.who] + let muster = game.where if (block_move(game.who) === 3) { for (let to of TOWNS[from].exits) { if (can_block_use_road_to_muster(from, to)) { if (to === muster || can_block_muster_with_2_moves(to, muster, from)) - gen_action(view, 'town', to); + gen_action(view, 'town', to) } } } else { for (let to of TOWNS[from].exits) { if (can_block_use_road_to_muster(from, to)) { if (to === muster || can_block_muster_with_1_move(to, muster)) - gen_action(view, 'town', to); + gen_action(view, 'town', to) } } } }, town: function (to) { - let from = game.location[game.who]; - log_move_start(from); - log_move_continue(to); - move_block(game.who, from, to); - lift_siege(from); + let from = game.location[game.who] + log_move_start(from) + log_move_continue(to) + move_block(game.who, from, to) + lift_siege(from) if (to === game.where) { - end_muster_move(); + end_muster_move() } else { - game.state = 'muster_move_2'; + game.state = 'muster_move_2' } }, block: pop_undo, @@ -2081,36 +2083,36 @@ states.muster_move_1 = { states.muster_move_2 = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; - view.prompt = "Muster: Move " + block_name(game.who) + " to " + game.where + "."; - view.muster = game.where; - gen_action_undo(view); - let from = game.location[game.who]; - let muster = game.where; + return view.prompt = "Move Phase: Waiting for " + game.active + "." + view.prompt = "Muster: Move " + block_name(game.who) + " to " + game.where + "." + view.muster = game.where + gen_action_undo(view) + let from = game.location[game.who] + let muster = game.where if (block_move(game.who) === 3) { for (let to of TOWNS[from].exits) { if (can_block_use_road_to_muster(from, to)) { if (to === muster || can_block_muster_with_1_move(to, muster)) - gen_action(view, 'town', to); + gen_action(view, 'town', to) } } } else { for (let to of TOWNS[from].exits) { if (can_block_use_road_to_muster(from, to)) { if (to === muster) - gen_action(view, 'town', to); + gen_action(view, 'town', to) } } } }, town: function (to) { - let from = game.location[game.who]; - log_move_continue(to); - move_block(game.who, from, to); + let from = game.location[game.who] + log_move_continue(to) + move_block(game.who, from, to) if (to === game.where) { - end_muster_move(); + end_muster_move() } else { - game.state = 'muster_move_3'; + game.state = 'muster_move_3' } }, undo: pop_undo, @@ -2119,33 +2121,33 @@ states.muster_move_2 = { states.muster_move_3 = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; - view.prompt = "Muster: Move " + block_name(game.who) + " to " + game.where + "."; - view.muster = game.where; - gen_action_undo(view); - let from = game.location[game.who]; - let muster = game.where; + return view.prompt = "Move Phase: Waiting for " + game.active + "." + view.prompt = "Muster: Move " + block_name(game.who) + " to " + game.where + "." + view.muster = game.where + gen_action_undo(view) + let from = game.location[game.who] + let muster = game.where for (let to of TOWNS[from].exits) { if (can_block_use_road_to_muster(from, to)) { if (to === muster) - gen_action(view, 'town', to); + gen_action(view, 'town', to) } } }, town: function (to) { - let from = game.location[game.who]; - log_move_continue(to); - move_block(game.who, from, to); - end_muster_move(); + let from = game.location[game.who] + log_move_continue(to) + move_block(game.who, from, to) + end_muster_move() }, undo: pop_undo, } function end_muster_move() { - log_move_end(); - game.moved[game.who] = 1; - game.who = null; - game.state = 'muster_who'; + log_move_end() + game.moved[game.who] = 1 + game.who = null + game.state = 'muster_who' } // WINTER CAMPAIGN @@ -2153,17 +2155,17 @@ function end_muster_move() { states.winter_campaign = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Move Phase: Waiting for " + game.active + "."; - view.prompt = "Winter Campaign: Select a siege to maintain over the winter."; - gen_action_undo(view); + return view.prompt = "Move Phase: Waiting for " + game.active + "." + view.prompt = "Winter Campaign: Select a siege to maintain over the winter." + gen_action_undo(view) for (let town of TOWNLIST) if (is_friendly_field(town) && is_under_siege(town)) - gen_action(view, 'town', town); + gen_action(view, 'town', town) }, town: function (where) { - log(game.active + " winter campaigned in " + where + "."); - game.winter_campaign = where; - game.state = 'move_phase'; + log(game.active + " winter campaigned in " + where + ".") + game.winter_campaign = where + game.state = 'move_phase' }, undo: pop_undo } @@ -2172,94 +2174,94 @@ states.winter_campaign = { function goto_combat_phase() { if (is_winter()) { - game.moved = {}; - return end_game_turn(); + game.moved = {} + return end_game_turn() } - game.combat_list = []; + game.combat_list = [] for (let where of TOWNLIST) if (is_contested_town(where)) - game.combat_list.push(where); - resume_combat_phase(); + game.combat_list.push(where) + resume_combat_phase() } function resume_combat_phase() { - reset_road_limits(); - reset_moved_for_combat(); + reset_road_limits() + reset_moved_for_combat() if (game.combat_list.length > 0) { - game.active = game.p1; - game.state = 'combat_phase'; + game.active = game.p1 + game.state = 'combat_phase' } else { - goto_draw_phase(); + goto_draw_phase() } } states.combat_phase = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Battle Phase: Waiting for " + game.active + "."; - view.prompt = "Battle Phase: Choose the next battle or siege!"; + return view.prompt = "Battle Phase: Waiting for " + game.active + "." + view.prompt = "Battle Phase: Choose the next battle or siege!" for (let where of game.combat_list) - gen_action(view, 'town', where); + gen_action(view, 'town', where) }, town: function (where) { - remove_from_array(game.combat_list, where); - game.where = where; - start_combat(); + remove_from_array(game.combat_list, where) + game.where = where + start_combat() }, } function start_combat() { - game.flash = ""; - log(""); - log("Battle in " + game.where); - game.combat_round = 0; - game.halfhit = null; - game.storming = []; - game.sallying = []; + game.flash = "" + log("") + log("Battle in " + game.where) + game.combat_round = 0 + game.halfhit = null + game.storming = [] + game.sallying = [] - game.show_castle = 0; - game.show_field = 0; + game.show_castle = 0 + game.show_field = 0 if (is_castle_town(game.where)) { if (!is_under_siege(game.where)) { - log("~ Combat Deployment ~"); - game.castle_owner = enemy(game.attacker[game.where]); - game.active = game.castle_owner; - game.state = 'combat_deployment'; - game.is_existing_siege = 0; + log("~ Combat Deployment ~") + game.castle_owner = enemy(game.attacker[game.where]) + game.active = game.castle_owner + game.state = 'combat_deployment' + game.is_existing_siege = 0 } else { - game.castle_owner = besieged_player(game.where); + game.castle_owner = besieged_player(game.where) if (!game.attacker[game.where]) - game.attacker[game.where] = enemy(game.castle_owner); - log("Existing siege continued."); - game.is_existing_siege = 1; - next_combat_round(); + game.attacker[game.where] = enemy(game.castle_owner) + log("Existing siege continued.") + game.is_existing_siege = 1 + next_combat_round() } } else { - game.castle_owner = null; - next_combat_round(); + game.castle_owner = null + next_combat_round() } } function end_combat() { - lift_siege(game.where); + lift_siege(game.where) if (game.jihad === game.where) - game.jihad = null; + game.jihad = null - delete game.is_existing_siege; - delete game.castle_owner; - delete game.storming; - delete game.sallying; - delete game.show_castle; - delete game.show_field; - game.where = null; - game.flash = ""; - game.combat_round = 0; + delete game.is_existing_siege + delete game.castle_owner + delete game.storming + delete game.sallying + delete game.show_castle + delete game.show_field + game.where = null + game.flash = "" + game.combat_round = 0 - resume_combat_phase(); + resume_combat_phase() } // COMBAT DEPLOYMENT @@ -2268,47 +2270,47 @@ states.combat_deployment = { show_battle: true, prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Battle: Waiting for " + game.active + "."; - view.prompt = "Battle: Deploy blocks on the field and in the castle."; - let max = castle_limit(game.where); - let n = count_blocks_in_castle(game.where); - let have_options = false; + return view.prompt = "Battle: Waiting for " + game.active + "." + view.prompt = "Battle: Deploy blocks on the field and in the castle." + let max = castle_limit(game.where) + let n = count_blocks_in_castle(game.where) + let have_options = false if (n < max) { for (let b of BLOCKLIST) { if (block_owner(b) === game.active && !is_reserve(b)) { if (game.location[b] === game.where && !game.castle.includes(b)) { - gen_action(view, 'withdraw', b); - gen_action(view, 'block', b); - have_options = true; + gen_action(view, 'withdraw', b) + gen_action(view, 'block', b) + have_options = true } } } } if (!have_options) - view.flash_next = "Click Next when you're done."; - gen_action_undo(view); - gen_action(view, 'next'); + view.flash_next = "Click Next when you're done." + gen_action_undo(view) + gen_action(view, 'next') }, withdraw: function (who) { - push_undo(); - game.castle.push(who); + push_undo() + game.castle.push(who) }, block: function (who) { - push_undo(); - game.castle.push(who); + push_undo() + game.castle.push(who) }, next: function () { - clear_undo(); - let n = count_blocks_in_castle(game.where); + clear_undo() + let n = count_blocks_in_castle(game.where) if (n === 1) - log(game.active + " withdrew 1 block."); + log(game.active + " withdrew 1 block.") else - log(game.active + " withdrew " + n + " blocks."); - game.active = game.attacker[game.where]; + log(game.active + " withdrew " + n + " blocks.") + game.active = game.attacker[game.where] if (count_enemy_in_field_and_reserve(game.where) === 0) { - return goto_regroup(); + return goto_regroup() } - next_combat_round(); + next_combat_round() }, undo: pop_undo } @@ -2317,47 +2319,47 @@ states.combat_deployment = { function print_retreat_summary() { if (game.summary && game.summary.length > 0) - print_summary("Retreated from " + game.where + ":"); + print_summary("Retreated from " + game.where + ":") } function goto_regroup() { - lift_siege(game.where); + lift_siege(game.where) if (!is_under_siege(game.where)) - clear_reserves(); // no siege battle, reserves arrive before regroup - reset_road_limits(); - reset_moved_for_combat(); - game.state = 'regroup'; - game.summary = []; + clear_reserves() // no siege battle, reserves arrive before regroup + reset_road_limits() + reset_moved_for_combat() + game.state = 'regroup' + game.summary = [] } states.regroup = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Regroup: Waiting for " + game.active + "."; - view.prompt = "Regroup: Choose a block to move."; - gen_action_undo(view); - gen_action(view, 'end_regroup'); + return view.prompt = "Regroup: Waiting for " + game.active + "." + view.prompt = "Regroup: Choose a block to move." + gen_action_undo(view) + gen_action(view, 'end_regroup') for (let b of BLOCKLIST) { if (game.location[b] === game.where) { if (can_block_regroup(b)) - gen_action(view, 'block', b); + gen_action(view, 'block', b) } } }, block: function (who) { - push_undo(); - game.who = who; - game.state = 'regroup_to'; + push_undo() + game.who = who + game.state = 'regroup_to' }, end_regroup: function () { - clear_undo(); - print_summary(game.active + " regrouped:", true); + clear_undo() + print_summary(game.active + " regrouped:", true) if (is_winter()) - goto_winter_2(); + goto_winter_2() else if (is_contested_town(game.where)) - next_combat_round(); + next_combat_round() else - end_combat(); + end_combat() }, undo: pop_undo } @@ -2365,24 +2367,24 @@ states.regroup = { states.regroup_to = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Regroup: Waiting for " + game.active + "."; - view.prompt = "Regroup: Move the block to a friendly or vacant town."; - gen_action_undo(view); - gen_action(view, 'block', game.who); + return view.prompt = "Regroup: Waiting for " + game.active + "." + view.prompt = "Regroup: Move the block to a friendly or vacant town." + gen_action_undo(view) + gen_action(view, 'block', game.who) for (let to of TOWNS[game.where].exits) if (can_block_regroup_to(game.who, to)) - gen_action(view, 'town', to); + gen_action(view, 'town', to) }, town: function (to) { // We can regroup while reserves are still on the way... - remove_from_array(game.reserves1, game.who); - remove_from_array(game.reserves2, game.who); + remove_from_array(game.reserves1, game.who) + remove_from_array(game.reserves2, game.who) - let from = game.where; - game.summary.push([from, to]); - move_block(game.who, game.where, to); - game.who = null; - game.state = 'regroup'; + let from = game.where + game.summary.push([from, to]) + move_block(game.who, game.where, to) + game.who = null + game.state = 'regroup' }, block: pop_undo, undo: pop_undo @@ -2391,287 +2393,287 @@ states.regroup_to = { // COMBAT ROUND function next_combat_round() { - print_retreat_summary(); + print_retreat_summary() if (game.jihad === game.where && game.combat_round === 1) - game.jihad = null; + game.jihad = null switch (game.combat_round) { - case 0: return goto_combat_round(1); - case 1: return goto_combat_round(2); - case 2: return goto_combat_round(3); - case 3: return goto_retreat_after_combat(); + case 0: return goto_combat_round(1) + case 1: return goto_combat_round(2) + case 2: return goto_combat_round(3) + case 3: return goto_retreat_after_combat() } } function bring_on_reserves(reserves) { - let f = 0; - let s = 0; + let f = 0 + let s = 0 for (let b of BLOCKLIST) { if (game.location[b] === game.where) { if (reserves.includes(b)) { if (block_owner(b) === FRANKS) - ++f; + ++f else - ++s; - remove_from_array(reserves, b); + ++s + remove_from_array(reserves, b) } } } if (f > 0) - log(f + " Frank " + (f === 1 ? "reserve arrived." : "reserves arrived.")); + log(f + " Frank " + (f === 1 ? "reserve arrived." : "reserves arrived.")) if (s > 0) - log(s + " Saracen " + (s === 1 ? "reserve arrived." : "reserves arrived.")); + log(s + " Saracen " + (s === 1 ? "reserve arrived." : "reserves arrived.")) } function clear_reserves(where) { for (let b of BLOCKLIST) { if (game.location[b] === where) { - remove_from_array(game.reserves1, b); - remove_from_array(game.reserves2, b); + remove_from_array(game.reserves1, b) + remove_from_array(game.reserves2, b) } } } function reset_moved_for_combat() { - for (let b in game.moved) game.moved[b] = 0; - for (let b of game.reserves1) game.moved[b] = 1; - for (let b of game.reserves2) game.moved[b] = 1; + for (let b in game.moved) game.moved[b] = 0 + for (let b of game.reserves1) game.moved[b] = 1 + for (let b of game.reserves2) game.moved[b] = 1 } function goto_combat_round(new_combat_round) { - game.combat_round = new_combat_round; - game.summary = []; + game.combat_round = new_combat_round + game.summary = [] - let was_contested = is_contested_battle_field(); + let was_contested = is_contested_battle_field() // If the main attack regroups away from a new siege while reinforcements // are on the way, we need to skip the first combat round. if (game.combat_round === 1 && is_under_siege(game.where)) { - game.active = besieging_player(game.where); + game.active = besieging_player(game.where) if (count_friendly_in_field_excluding_reserves(game.where) === 0) { - log("Combat round skipped because main attack regrouped away."); - game.combat_round = 2; + log("Combat round skipped because main attack regrouped away.") + game.combat_round = 2 } } - log("~ Combat Round " + game.combat_round + " ~"); + log("~ Combat Round " + game.combat_round + " ~") if (game.combat_round === 2) - bring_on_reserves(game.reserves1); + bring_on_reserves(game.reserves1) if (game.combat_round === 3) - bring_on_reserves(game.reserves2); + bring_on_reserves(game.reserves2) - reset_moved_for_combat(); + reset_moved_for_combat() if (is_contested_battle_field()) { if (is_under_siege(game.where)) { if (!was_contested) { - log("Relief forces arrived!"); + log("Relief forces arrived!") if (game.storming.length > 0) { - log("Storming canceled by arriving relief force."); - game.halfhit = null; - game.storming.length = 0; + log("Storming canceled by arriving relief force.") + game.halfhit = null + game.storming.length = 0 } - let old_attacker = game.attacker[game.where]; - game.attacker[game.where] = besieged_player(game.where); + let old_attacker = game.attacker[game.where] + game.attacker[game.where] = besieged_player(game.where) if (old_attacker !== game.attacker[game.where]) { - log(game.attacker[game.where] + " are now the attacker."); + log(game.attacker[game.where] + " are now the attacker.") } } // No sally first round after combat deployment. if (game.combat_round > 1 || game.is_existing_siege) - return goto_declare_sally(); + return goto_declare_sally() } - return goto_field_battle(); + return goto_field_battle() } - goto_declare_storm(); + goto_declare_storm() } // DECLARE STORM function goto_declare_storm() { - game.active = besieging_player(game.where); + game.active = besieging_player(game.where) // Castle is full. if (game.storming.length === castle_limit(game.where)) - return goto_siege_battle(); + return goto_siege_battle() // Field is empty. if (count_friendly(game.where) - game.storming.length === 0) - return goto_siege_battle(); - game.state = 'declare_storm'; + return goto_siege_battle() + game.state = 'declare_storm' } states.declare_storm = { show_battle: true, prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Siege Declaration: Waiting for " + game.active + " to declare storm."; - view.prompt = "Siege Declaration: Declare which blocks should storm the castle."; - let have_options = false; + return view.prompt = "Siege Declaration: Waiting for " + game.active + " to declare storm." + view.prompt = "Siege Declaration: Declare which blocks should storm the castle." + let have_options = false if (game.storming.length < castle_limit(game.where)) { for (let b of BLOCKLIST) { if (block_owner(b) === game.active && !is_reserve(b)) { if (game.location[b] === game.where && !game.storming.includes(b)) { - gen_action(view, 'storm', b); - gen_action(view, 'block', b); - have_options = true; + gen_action(view, 'storm', b) + gen_action(view, 'block', b) + have_options = true } } } } if (!have_options) - view.flash_next = "Click Next when you're done."; - gen_action_undo(view); - gen_action(view, 'next'); + view.flash_next = "Click Next when you're done." + gen_action_undo(view) + gen_action(view, 'next') }, storm: storm_with_block, block: storm_with_block, next: function () { - clear_undo(); - let n = game.storming.length; + clear_undo() + let n = game.storming.length if (n === 0) { - game.flash = game.active + " declined to storm."; + game.flash = game.active + " declined to storm." if (game.jihad === game.where) - game.jihad = null; - log(game.active + " declined to storm."); - goto_declare_sally(); + game.jihad = null + log(game.active + " declined to storm.") + goto_declare_sally() } else { - goto_siege_battle(); + goto_siege_battle() } }, undo: pop_undo } function storm_with_block(who) { - push_undo(); - game.storming.push(who); + push_undo() + game.storming.push(who) if (game.storming.length > 1) - game.flash = game.active + " stormed with " + game.storming.length + " blocks."; + game.flash = game.active + " stormed with " + game.storming.length + " blocks." else - game.flash = game.active + " stormed with 1 block."; - log(game.active[0] + ": " + block_name(who) + " stormed."); + game.flash = game.active + " stormed with 1 block." + log(game.active[0] + ": " + block_name(who) + " stormed.") } // DECLARE SALLY function goto_declare_sally() { - game.active = besieged_player(game.where); - game.state = 'declare_sally'; - game.was_contested = is_contested_battle_field(); + game.active = besieged_player(game.where) + game.state = 'declare_sally' + game.was_contested = is_contested_battle_field() } states.declare_sally = { show_battle: true, prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Siege Declaration: Waiting for " + game.active + " to declare sally."; - view.prompt = "Siege Declaration: Declare which blocks should sally onto the field."; - let have_options = false; + return view.prompt = "Siege Declaration: Waiting for " + game.active + " to declare sally." + view.prompt = "Siege Declaration: Declare which blocks should sally onto the field." + let have_options = false for (let b of BLOCKLIST) { if (block_owner(b) === game.active && !is_reserve(b) && is_block_in_castle(b)) { if (game.location[b] === game.where && !game.sallying.includes(b)) { - gen_action(view, 'sally', b); - gen_action(view, 'block', b); - have_options = true; + gen_action(view, 'sally', b) + gen_action(view, 'block', b) + have_options = true } } } if (!have_options) - view.flash_next = "Click Next when you're done."; - gen_action_undo(view); - gen_action(view, 'next'); + view.flash_next = "Click Next when you're done." + gen_action_undo(view) + gen_action(view, 'next') }, sally: sally_with_block, block: sally_with_block, next: function () { - clear_undo(); - let n = game.sallying.length; + clear_undo() + let n = game.sallying.length if (n === 0) { - game.flash = game.active + " declined to sally."; - log(game.active + " declined to sally."); + game.flash = game.active + " declined to sally." + log(game.active + " declined to sally.") } if (is_contested_battle_field()) { if (!game.was_contested) { - log(game.active + " are now the attacker."); - game.attacker[game.where] = game.active; + log(game.active + " are now the attacker.") + game.attacker[game.where] = game.active } - goto_field_battle(); + goto_field_battle() } else if (count_reserves(game.where) > 0) { - next_combat_round(); + next_combat_round() } else { - goto_siege_attrition(); + goto_siege_attrition() } }, undo: pop_undo } function sally_with_block(who) { - push_undo(); - remove_from_array(game.castle, who); - game.sallying.push(who); + push_undo() + remove_from_array(game.castle, who) + game.sallying.push(who) if (game.sallying.length > 1) - game.flash = game.active + " sallied with " + game.sallying.length + " blocks."; + game.flash = game.active + " sallied with " + game.sallying.length + " blocks." else - game.flash = game.active + " sallied with 1 block."; - log(game.active[0] + ": " + block_name(who) + " sallied."); + game.flash = game.active + " sallied with 1 block." + log(game.active[0] + ": " + block_name(who) + " sallied.") } // RETREAT AFTER COMBAT function goto_retreat_after_combat() { - reset_moved_for_combat(); + reset_moved_for_combat() // withdraw all sallying blocks to castle. for (let b of game.sallying) - game.castle.push(b); - game.sallying.length = 0; + game.castle.push(b) + game.sallying.length = 0 // TODO: 6.2 - In Sieges, the attacker /may/ retreat or stay on siege. // withdraw all storming blocks to the field. - game.halfhit = null; - game.storming.length = 0; + game.halfhit = null + game.storming.length = 0 if (is_contested_field(game.where)) { - log("~ Retreat ~"); - game.active = game.attacker[game.where]; - game.state = 'retreat'; - game.summary = []; + log("~ Retreat ~") + game.active = game.attacker[game.where] + game.state = 'retreat' + game.summary = [] } else if (is_under_siege(game.where)) { - goto_siege_attrition(); + goto_siege_attrition() } else { - end_combat(); + end_combat() } } states.retreat = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Retreat: Waiting for " + game.active + "."; - view.prompt = "Retreat: Choose a block to move."; - gen_action_undo(view); - let can_retreat = false; + return view.prompt = "Retreat: Waiting for " + game.active + "." + view.prompt = "Retreat: Choose a block to move." + gen_action_undo(view) + let can_retreat = false for (let b of BLOCKLIST) { if (game.location[b] === game.where && !is_block_in_castle(b) && can_block_retreat(b)) { - gen_action(view, 'block', b); - can_retreat = true; + gen_action(view, 'block', b) + can_retreat = true } } if (!is_contested_field(game.where) || !can_retreat) - gen_action(view, 'end_retreat'); + gen_action(view, 'end_retreat') }, end_retreat: function () { - clear_undo(); + clear_undo() for (let b of BLOCKLIST) if (game.location[b] === game.where && !is_block_in_castle(b) && block_owner(b) === game.active) - eliminate_block(b); - print_summary(game.active + " retreated:"); - game.active = enemy(game.active); - goto_regroup(); + eliminate_block(b) + print_summary(game.active + " retreated:") + game.active = enemy(game.active) + goto_regroup() }, block: function (who) { - push_undo(); - game.who = who; - game.state = 'retreat_to'; + push_undo() + game.who = who + game.state = 'retreat_to' }, undo: pop_undo } @@ -2679,31 +2681,31 @@ states.retreat = { states.retreat_to = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Retreat: Waiting for " + game.active + "."; - view.prompt = "Retreat: Move the block to a friendly or neutral town."; - gen_action_undo(view); - gen_action(view, 'block', game.who); - let can_retreat = false; + return view.prompt = "Retreat: Waiting for " + game.active + "." + view.prompt = "Retreat: Move the block to a friendly or neutral town." + gen_action_undo(view) + gen_action(view, 'block', game.who) + let can_retreat = false for (let to of TOWNS[game.where].exits) { if (can_block_retreat_to(game.who, to)) { - gen_action(view, 'town', to); - can_retreat = true; + gen_action(view, 'town', to) + can_retreat = true } } if (!can_retreat) - gen_action(view, 'eliminate'); + gen_action(view, 'eliminate') }, town: function (to) { - let from = game.where; - game.summary.push([from, to]); - move_block(game.who, game.where, to); - game.who = null; - game.state = 'retreat'; + let from = game.where + game.summary.push([from, to]) + move_block(game.who, game.where, to) + game.who = null + game.state = 'retreat' }, eliminate: function () { - eliminate_block(game.who); - game.who = null; - game.state = 'retreat'; + eliminate_block(game.who) + game.who = null + game.state = 'retreat' }, block: pop_undo, undo: pop_undo @@ -2712,25 +2714,25 @@ states.retreat_to = { // SIEGE ATTRITION function goto_siege_attrition() { - log("~ Siege Attrition ~"); - game.active = besieged_player(game.where); - game.state = 'siege_attrition'; - game.attrition_list = []; + log("~ Siege Attrition ~") + game.active = besieged_player(game.where) + game.state = 'siege_attrition' + game.attrition_list = [] for (let b of BLOCKLIST) if (is_block_in_castle_in(b, game.where)) - game.attrition_list.push(b); + game.attrition_list.push(b) } function resume_siege_attrition() { if (game.attrition_list.length === 0) { - delete game.attrition_list; + delete game.attrition_list if (!is_under_siege(game.where)) { - game.active = enemy(game.active); - log(game.where + " fell to siege attrition."); - goto_regroup(); + game.active = enemy(game.active) + log(game.where + " fell to siege attrition.") + goto_regroup() } else { - log("Siege continued."); - end_combat(); + log("Siege continued.") + end_combat() } } } @@ -2738,157 +2740,157 @@ function resume_siege_attrition() { states.siege_attrition = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Siege Attrition: Waiting for " + game.active + "."; - view.prompt = "Siege Attrition: Roll for siege attrition in " + game.where + "."; + return view.prompt = "Siege Attrition: Waiting for " + game.active + "." + view.prompt = "Siege Attrition: Roll for siege attrition in " + game.where + "." for (let b of game.attrition_list) gen_action(view, 'block', b) }, block: function (who) { - let target = (game.where === TYRE || game.where === TRIPOLI) ? 1 : 3; - let die = roll_d6(); + let target = (game.where === TYRE || game.where === TRIPOLI) ? 1 : 3 + let die = roll_d6() if (die <= target) { - log("Attrition roll " + DIE_HIT[die] + "."); - reduce_block(who); + log("Attrition roll " + DIE_HIT[die] + ".") + reduce_block(who) } else { - log("Attrition roll " + DIE_MISS[die] + "."); + log("Attrition roll " + DIE_MISS[die] + ".") } - remove_from_array(game.attrition_list, who); - resume_siege_attrition(); + remove_from_array(game.attrition_list, who) + resume_siege_attrition() } } // FIELD AND SIEGE BATTLE HELPERS function filter_battle_blocks(ci, is_candidate) { - let output = null; + let output = null for (let b of BLOCKLIST) { if (is_candidate(b) && !game.moved[b]) { if (block_initiative(b) === ci) { if (!output) - output = []; - output.push(b); + output = [] + output.push(b) } } } - return output; + return output } function battle_step(active, initiative, candidate) { - game.battle_list = filter_battle_blocks(initiative, candidate); + game.battle_list = filter_battle_blocks(initiative, candidate) if (game.battle_list) { - game.active = active; - return true; + game.active = active + return true } - return false; + return false } function pump_battle_step(is_candidate_attacker, is_candidate_defender) { - let attacker = game.attacker[game.where]; - let defender = enemy(attacker); + let attacker = game.attacker[game.where] + let defender = enemy(attacker) if (game.jihad === game.where && game.combat_round === 1) { - if (battle_step(attacker, 'A', is_candidate_attacker)) return; - if (battle_step(attacker, 'B', is_candidate_attacker)) return; - if (battle_step(attacker, 'C', is_candidate_attacker)) return; - if (battle_step(defender, 'A', is_candidate_defender)) return; - if (battle_step(defender, 'B', is_candidate_defender)) return; - if (battle_step(defender, 'C', is_candidate_defender)) return; + if (battle_step(attacker, 'A', is_candidate_attacker)) return + if (battle_step(attacker, 'B', is_candidate_attacker)) return + if (battle_step(attacker, 'C', is_candidate_attacker)) return + if (battle_step(defender, 'A', is_candidate_defender)) return + if (battle_step(defender, 'B', is_candidate_defender)) return + if (battle_step(defender, 'C', is_candidate_defender)) return } else { - if (battle_step(defender, 'A', is_candidate_defender)) return; - if (battle_step(attacker, 'A', is_candidate_attacker)) return; - if (battle_step(defender, 'B', is_candidate_defender)) return; - if (battle_step(attacker, 'B', is_candidate_attacker)) return; - if (battle_step(defender, 'C', is_candidate_defender)) return; - if (battle_step(attacker, 'C', is_candidate_attacker)) return; + if (battle_step(defender, 'A', is_candidate_defender)) return + if (battle_step(attacker, 'A', is_candidate_attacker)) return + if (battle_step(defender, 'B', is_candidate_defender)) return + if (battle_step(attacker, 'B', is_candidate_attacker)) return + if (battle_step(defender, 'C', is_candidate_defender)) return + if (battle_step(attacker, 'C', is_candidate_attacker)) return } - next_combat_round(); + next_combat_round() } // FIELD BATTLE function goto_field_battle() { - resume_field_battle(); + resume_field_battle() } function resume_field_battle() { // we have a queued up harry action if (game.harry) { - game.active = game.harry; - game.state = 'harry'; - delete game.harry; - return; + game.active = game.harry + game.state = 'harry' + delete game.harry + return } - game.active = game.attacker[game.where]; + game.active = game.attacker[game.where] if (is_friendly_field(game.where)) { - print_retreat_summary(); - log("Field battle won by " + game.active + "."); - game.show_field = 0; - return goto_regroup(); + print_retreat_summary() + log("Field battle won by " + game.active + ".") + game.show_field = 0 + return goto_regroup() } if (is_enemy_field(game.where)) { - game.active = enemy(game.active); - print_retreat_summary(); - log("Field battle won by " + game.active + "."); - game.show_field = 0; - return goto_regroup(); + game.active = enemy(game.active) + print_retreat_summary() + log("Field battle won by " + game.active + ".") + game.show_field = 0 + return goto_regroup() } if (is_enemy_battle_field()) { - print_retreat_summary(); - log("Attacking main force was eliminated."); - return next_combat_round(); + print_retreat_summary() + log("Attacking main force was eliminated.") + return next_combat_round() } if (is_friendly_battle_field()) { - print_retreat_summary(); - log("Defending main force was eliminated."); - log("Battlefield control changed."); - game.attacker[game.where] = enemy(game.active); + print_retreat_summary() + log("Defending main force was eliminated.") + log("Battlefield control changed.") + game.attacker[game.where] = enemy(game.active) // The new defender takes control of the empty castle if (!is_under_siege(game.where)) - game.castle_owner = game.active; - return next_combat_round(); + game.castle_owner = game.active + return next_combat_round() } - game.state = 'field_battle'; - game.show_field = 1; - pump_battle_step(is_field_attacker, is_field_defender); + game.state = 'field_battle' + game.show_field = 1 + pump_battle_step(is_field_attacker, is_field_defender) } states.field_battle = { show_battle: true, prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Field Battle: Waiting for " + game.active + "."; - view.prompt = "Field Battle: Choose a combat action."; + return view.prompt = "Field Battle: Waiting for " + game.active + "." + view.prompt = "Field Battle: Choose a combat action." for (let b of game.battle_list) { - gen_action(view, 'block', b); // take default action - gen_action(view, 'fire', b); + gen_action(view, 'block', b) // take default action + gen_action(view, 'fire', b) if (game.sallying.includes(b)) { // Only sallying forces may withdraw into the castle - gen_action(view, 'withdraw', b); + gen_action(view, 'withdraw', b) } else { if (can_block_retreat(b)) { - gen_action(view, 'retreat', b); + gen_action(view, 'retreat', b) // Turcopoles and Nomads can Harry (fire and retreat) if (block_type(b) === 'turcopoles' || block_type(b) === 'nomads') - gen_action(view, 'harry', b); + gen_action(view, 'harry', b) } // Defender can withdraw into castle if friendly and there is room. if (game.active !== game.attacker[game.where] && game.active === game.castle_owner) { // TODO: allow swapping place of sallying block, leaving it to die if it cannot withdraw? if (game.sallying.length + count_blocks_in_castle(game.where) < castle_limit(game.where)) - gen_action(view, 'withdraw', b); + gen_action(view, 'withdraw', b) } } // All Frank B blocks are knights who can Charge if (block_owner(b) === FRANKS && block_initiative(b) === 'B') - gen_action(view, 'charge', b); + gen_action(view, 'charge', b) } }, block: field_fire_with_block, @@ -2902,57 +2904,57 @@ states.field_battle = { // SIEGE BATTLE function goto_siege_battle() { - game.attacker[game.where] = besieging_player(game.where); - game.show_castle = 1; - resume_siege_battle(); + game.attacker[game.where] = besieging_player(game.where) + game.show_castle = 1 + resume_siege_battle() } function resume_siege_battle() { - game.active = game.attacker[game.where]; + game.active = game.attacker[game.where] if (is_friendly_town(game.where)) { - log("Siege battle won by " + game.active + "."); - return goto_regroup(); + log("Siege battle won by " + game.active + ".") + return goto_regroup() } if (is_enemy_town(game.where)) { - game.active = enemy(game.active); - game.halfhit = null; - log("Siege battle won by " + game.active + "."); - return goto_regroup(); + game.active = enemy(game.active) + game.halfhit = null + log("Siege battle won by " + game.active + ".") + return goto_regroup() } if (count_blocks_in_castle(game.where) === 0) { - log("Defending main force was eliminated."); - log(game.active + " are now the defender."); - game.attacker[game.where] = enemy(game.active); + log("Defending main force was eliminated.") + log(game.active + " are now the defender.") + game.attacker[game.where] = enemy(game.active) // The new defender takes control of the empty castle - game.castle_owner = game.active; - game.storming.length = 0; - return next_combat_round(); + game.castle_owner = game.active + game.storming.length = 0 + return next_combat_round() } if (game.storming.length === 0) { - game.halfhit = null; - log("Storming repulsed."); - return next_combat_round(); + game.halfhit = null + log("Storming repulsed.") + return next_combat_round() } - game.state = 'siege_battle'; - pump_battle_step(is_siege_attacker, is_siege_defender); + game.state = 'siege_battle' + pump_battle_step(is_siege_attacker, is_siege_defender) } states.siege_battle = { show_battle: true, prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Siege Battle: Waiting for " + game.active + "."; - view.prompt = "Siege Battle: Choose a combat action."; + return view.prompt = "Siege Battle: Waiting for " + game.active + "." + view.prompt = "Siege Battle: Choose a combat action." for (let b of game.battle_list) { - gen_action(view, 'block', b); // take default action - gen_action(view, 'fire', b); + gen_action(view, 'block', b) // take default action + gen_action(view, 'fire', b) if (game.storming.includes(b)) - gen_action(view, 'retreat', b); + gen_action(view, 'retreat', b) } }, block: siege_fire_with_block, @@ -2963,35 +2965,35 @@ states.siege_battle = { // FIELD BATTLE HITS function goto_field_battle_hits() { - game.active = enemy(game.active); - game.battle_list = list_field_victims(); + game.active = enemy(game.active) + game.battle_list = list_field_victims() if (game.battle_list.length === 0) - resume_field_battle(); + resume_field_battle() else - game.state = 'field_battle_hits'; + game.state = 'field_battle_hits' } function list_field_victims() { - let max = 0; + let max = 0 for (let b of BLOCKLIST) if (block_owner(b) === game.active && is_field_combatant(b) && game.steps[b] > max) - max = game.steps[b]; - let list = []; + max = game.steps[b] + let list = [] for (let b of BLOCKLIST) if (block_owner(b) === game.active && is_field_combatant(b) && game.steps[b] === max) - list.push(b); - return list; + list.push(b) + return list } states.field_battle_hits = { show_battle: true, prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Field Battle: Waiting for " + game.active + " to assign hits."; - view.prompt = "Field Battle: Assign " + game.hits + (game.hits !== 1 ? " hits" : " hit") + " to your armies."; + return view.prompt = "Field Battle: Waiting for " + game.active + " to assign hits." + view.prompt = "Field Battle: Assign " + game.hits + (game.hits !== 1 ? " hits" : " hit") + " to your armies." for (let b of game.battle_list) { - gen_action(view, 'hit', b); - gen_action(view, 'block', b); + gen_action(view, 'hit', b) + gen_action(view, 'block', b) } }, hit: apply_field_battle_hit, @@ -2999,62 +3001,62 @@ states.field_battle_hits = { } function apply_field_battle_hit_to(who, flash) { - let msg; - msg = block_name(who) + " took a hit."; - log(game.active[0] + ": " + msg); + let msg + msg = block_name(who) + " took a hit." + log(game.active[0] + ": " + msg) if (flash) - game.flash = msg; - reduce_block(who); - game.hits--; + game.flash = msg + reduce_block(who) + game.hits-- } function apply_field_battle_hit(who) { - apply_field_battle_hit_to(who, true); + apply_field_battle_hit_to(who, true) if (game.hits === 0) - resume_field_battle(); + resume_field_battle() else { - game.battle_list = list_field_victims(); + game.battle_list = list_field_victims() if (game.battle_list.length === 0) - resume_field_battle(); + resume_field_battle() else - game.flash += " " + game.hits + (game.hits === 1 ? " hit left." : " hits left."); + game.flash += " " + game.hits + (game.hits === 1 ? " hit left." : " hits left.") } } // SIEGE BATTLE HITS function goto_siege_battle_hits() { - game.active = enemy(game.active); - game.battle_list = list_siege_victims(); + game.active = enemy(game.active) + game.battle_list = list_siege_victims() if (game.battle_list.length === 0) - resume_siege_battle(); + resume_siege_battle() else - game.state = 'siege_battle_hits'; + game.state = 'siege_battle_hits' } function list_siege_victims() { if (game.halfhit && block_owner(game.halfhit) === game.active) - return [ game.halfhit ]; - let max = 0; + return [ game.halfhit ] + let max = 0 for (let b of BLOCKLIST) if (block_owner(b) === game.active && is_siege_combatant(b) && game.steps[b] > max) - max = game.steps[b]; - let list = []; + max = game.steps[b] + let list = [] for (let b of BLOCKLIST) if (block_owner(b) === game.active && is_siege_combatant(b) && game.steps[b] === max) - list.push(b); - return list; + list.push(b) + return list } states.siege_battle_hits = { show_battle: true, prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Siege Battle: Waiting for " + game.active + " to assign hits."; - view.prompt = "Siege Battle: Assign " + game.hits + (game.hits !== 1 ? " hits" : " hit") + " to your armies."; + return view.prompt = "Siege Battle: Waiting for " + game.active + " to assign hits." + view.prompt = "Siege Battle: Assign " + game.hits + (game.hits !== 1 ? " hits" : " hit") + " to your armies." for (let b of game.battle_list) { - gen_action(view, 'hit', b); - gen_action(view, 'block', b); + gen_action(view, 'hit', b) + gen_action(view, 'block', b) } }, hit: apply_siege_battle_hit, @@ -3062,38 +3064,38 @@ states.siege_battle_hits = { } function apply_siege_battle_hit_to(who, flash) { - let msg = block_name(who) + " took a "; + let msg = block_name(who) + " took a " if (game.halfhit === who) { - msg += "hit."; - log(game.active[0] + ": " + msg); - reduce_block(who); - game.halfhit = null; + msg += "hit." + log(game.active[0] + ": " + msg) + reduce_block(who) + game.halfhit = null } else { if (is_block_in_castle(who)) { - msg += "half-hit."; - log(game.active[0] + ": " + msg); - game.halfhit = who; + msg += "half-hit." + log(game.active[0] + ": " + msg) + game.halfhit = who } else { - msg += "hit."; - log(game.active[0] + ": " + msg); - reduce_block(who); + msg += "hit." + log(game.active[0] + ": " + msg) + reduce_block(who) } } if (flash) - game.flash = msg; - game.hits--; + game.flash = msg + game.hits-- } function apply_siege_battle_hit(who) { - apply_siege_battle_hit_to(who, true); + apply_siege_battle_hit_to(who, true) if (game.hits === 0) { - resume_siege_battle(); + resume_siege_battle() } else { - game.battle_list = list_siege_victims(); + game.battle_list = list_siege_victims() if (game.battle_list.length === 0) { - resume_siege_battle(); + resume_siege_battle() } else { - game.flash += " " + game.hits + (game.hits === 1 ? " hit left." : " hits left."); + game.flash += " " + game.hits + (game.hits === 1 ? " hit left." : " hits left.") } } } @@ -3101,305 +3103,305 @@ function apply_siege_battle_hit(who) { // BATTLE ACTIONS function roll_attack(active, b, verb, is_charge) { - game.hits = 0; - let fire = block_fire_power(b, game.where) + is_charge; - let rolls = []; - let steps = game.steps[b]; - let name = block_name(b) + " " + BLOCKS[b].combat; - let self = 0; + game.hits = 0 + let fire = block_fire_power(b, game.where) + is_charge + let rolls = [] + let steps = game.steps[b] + let name = block_name(b) + " " + BLOCKS[b].combat + let self = 0 for (let i = 0; i < steps; ++i) { - let die = roll_d6(); + let die = roll_d6() if (die <= fire) { - rolls.push(DIE_HIT[die]); - ++game.hits; + rolls.push(DIE_HIT[die]) + ++game.hits } else { if (is_charge && die === 6) { - rolls.push(DIE_SELF); - ++self; + rolls.push(DIE_SELF) + ++self } else { - rolls.push(DIE_MISS[die]); + rolls.push(DIE_MISS[die]) } } } - game.flash = name + " " + verb + " " + rolls.join(" ") + " "; + game.flash = name + " " + verb + " " + rolls.join(" ") + " " if (game.hits === 0) - game.flash += "and missed."; + game.flash += "and missed." else if (game.hits === 1) - game.flash += "and scored 1 hit."; + game.flash += "and scored 1 hit." else - game.flash += "and scored " + game.hits + " hits."; + game.flash += "and scored " + game.hits + " hits." if (self > 0) { if (self === 1) - game.flash += " " + self + " self hit."; + game.flash += " " + self + " self hit." else - game.flash += " " + self + " self hits."; - self = Math.min(self, game.steps[b]); + game.flash += " " + self + " self hits." + self = Math.min(self, game.steps[b]) while (self-- > 0) - reduce_block(b); + reduce_block(b) } - log(active[0] + ": " + name + " " + verb + " " + rolls.join("") + "."); + log(active[0] + ": " + name + " " + verb + " " + rolls.join("") + ".") } function field_fire_with_block(b) { - game.moved[b] = 1; - roll_attack(game.active, b, "fired", 0); + game.moved[b] = 1 + roll_attack(game.active, b, "fired", 0) if (game.hits > 0) { - goto_field_battle_hits(); + goto_field_battle_hits() } else { - resume_field_battle(); + resume_field_battle() } } function siege_fire_with_block(b) { - game.moved[b] = 1; - roll_attack(game.active, b, "fired", 0); + game.moved[b] = 1 + roll_attack(game.active, b, "fired", 0) if (game.hits > 0) { - goto_siege_battle_hits(); + goto_siege_battle_hits() } else { - resume_siege_battle(); + resume_siege_battle() } } function charge_with_block(b) { - game.moved[b] = 1; - roll_attack(game.active, b, "charged", 1); + game.moved[b] = 1 + roll_attack(game.active, b, "charged", 1) if (game.hits > 0) { - goto_field_battle_hits(); + goto_field_battle_hits() } else { - resume_field_battle(); + resume_field_battle() } } function field_withdraw_with_block(b) { - game.flash = b + " withdrew."; - log(game.active[0] + ": " + game.flash); - game.moved[b] = 1; - remove_from_array(game.sallying, b); - game.castle.push(b); - resume_field_battle(); + game.flash = b + " withdrew." + log(game.active[0] + ": " + game.flash) + game.moved[b] = 1 + remove_from_array(game.sallying, b) + game.castle.push(b) + resume_field_battle() } function siege_withdraw_with_block(b) { - game.flash = b + " withdrew."; - log(game.active[0] + ": " + game.flash); - game.moved[b] = 1; - remove_from_array(game.storming, b); - resume_siege_battle(); + game.flash = b + " withdrew." + log(game.active[0] + ": " + game.flash) + game.moved[b] = 1 + remove_from_array(game.storming, b) + resume_siege_battle() } function harry_with_block(b) { - game.harry = game.active; // remember to retreat after hits have been applied - game.who = b; - roll_attack(game.active, b, "harried", 0); + game.harry = game.active // remember to retreat after hits have been applied + game.who = b + roll_attack(game.active, b, "harried", 0) if (game.hits > 0) { - goto_field_battle_hits(); + goto_field_battle_hits() } else { - resume_field_battle(); + resume_field_battle() } } states.harry = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Field Battle: Waiting for " + game.active + " to retreat the harrying block."; - view.prompt = "Field Battle: Retreat the harrying block to a friendly or vacant town."; + return view.prompt = "Field Battle: Waiting for " + game.active + " to retreat the harrying block." + view.prompt = "Field Battle: Retreat the harrying block to a friendly or vacant town." for (let to of TOWNS[game.where].exits) if (can_block_retreat_to(game.who, to)) - gen_action(view, 'town', to); + gen_action(view, 'town', to) }, town: function (to) { - game.flash += " " + block_name(game.who) + " retreated."; - game.summary.push([game.active, to]); - game.location[game.who] = to; - move_block(game.who, game.where, to); - game.who = null; - resume_field_battle(); + game.flash += " " + block_name(game.who) + " retreated." + game.summary.push([game.active, to]) + game.location[game.who] = to + move_block(game.who, game.where, to) + game.who = null + resume_field_battle() }, } function retreat_with_block(b) { - game.who = b; - game.state = 'retreat_in_battle'; + game.who = b + game.state = 'retreat_in_battle' } states.retreat_in_battle = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Field Battle: Waiting for " + game.active + " to retreat."; - gen_action(view, 'undo'); - gen_action(view, 'block', game.who); - view.prompt = "Field Battle: Retreat the block to a friendly or vacant town."; + return view.prompt = "Field Battle: Waiting for " + game.active + " to retreat." + gen_action(view, 'undo') + gen_action(view, 'block', game.who) + view.prompt = "Field Battle: Retreat the block to a friendly or vacant town." for (let to of TOWNS[game.where].exits) if (can_block_retreat_to(game.who, to)) - gen_action(view, 'town', to); + gen_action(view, 'town', to) }, town: function (to) { - game.flash = block_name(game.who) + " retreated."; - log(game.active[0] + ": " + game.flash); - game.summary.push([game.active, to]); - game.location[game.who] = to; - move_block(game.who, game.where, to); - game.who = null; - resume_field_battle(); + game.flash = block_name(game.who) + " retreated." + log(game.active[0] + ": " + game.flash) + game.summary.push([game.active, to]) + game.location[game.who] = to + move_block(game.who, game.where, to) + game.who = null + resume_field_battle() }, block: function () { - game.who = null; - resume_field_battle(); + game.who = null + resume_field_battle() }, undo: function () { - game.who = null; - resume_field_battle(); + game.who = null + resume_field_battle() } } // DRAW PHASE function goto_draw_phase() { - delete game.combat_list; + delete game.combat_list if (game.year > 1187 && !is_winter()) { - game.active = game.p1; - log(""); - start_draw_phase(); + game.active = game.p1 + log("") + start_draw_phase() } else { - end_game_turn(); + end_game_turn() } } function start_draw_phase() { - game.state = 'draw_phase'; + game.state = 'draw_phase' if (game.active === FRANKS) { - game.who = select_random_block(F_POOL); + game.who = select_random_block(F_POOL) if (!game.who) - end_draw_phase(); + end_draw_phase() } else { - game.who = select_random_block(S_POOL); + game.who = select_random_block(S_POOL) if (!game.who) - end_draw_phase(); + end_draw_phase() } } states.draw_phase = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Draw Phase: Waiting for " + game.active + "."; - let can_place = false; + return view.prompt = "Draw Phase: Waiting for " + game.active + "." + let can_place = false switch (block_type(game.who)) { case 'crusaders': - view.prompt = "Draw Phase: Place " + block_name(game.who) + " in the staging area."; - gen_action(view, 'town', block_home(game.who)); - can_place = true; - break; + view.prompt = "Draw Phase: Place " + block_name(game.who) + " in the staging area." + gen_action(view, 'town', block_home(game.who)) + can_place = true + break case 'pilgrims': - view.prompt = "Draw Phase: Place " + block_name(game.who) + " in a friendly port."; + view.prompt = "Draw Phase: Place " + block_name(game.who) + " in a friendly port." for (let town of TOWNLIST) { if (is_friendly_port(town) || can_enter_besieged_port(town)) { - gen_action(view, 'town', town); - can_place = true; + gen_action(view, 'town', town) + can_place = true } } - break; + break case 'turcopoles': case 'outremers': case 'emirs': case 'nomads': view.prompt = "Draw Phase: Place " + BLOCKS[game.who].name + " at full strength in " - + list_seats(game.who).join(", ") + " or at strength 1 in any friendly town."; + + list_seats(game.who).join(", ") + " or at strength 1 in any friendly town." for (let town of TOWNLIST) { if (town === ENGLAND || town === FRANCE || town === GERMANIA) - continue; + continue // FAQ claims besieger controls town for draw purposes if (is_friendly_field(town)) { - gen_action(view, 'town', town); - can_place = true; + gen_action(view, 'town', town) + can_place = true } } - break; + break } if (!can_place) - gen_action(view, 'next'); + gen_action(view, 'next') }, town: function (where) { - let type = block_type(game.who); + let type = block_type(game.who) - log(game.active + " placed drawn block in " + where + "."); + log(game.active + " placed drawn block in " + where + ".") - game.location[game.who] = where; + game.location[game.who] = where if (type === 'turcopoles' || type === 'outremers' || type === 'emirs' || type === 'nomads') { if (is_home_seat(where, game.who)) - game.steps[game.who] = block_max_steps(game.who); + game.steps[game.who] = block_max_steps(game.who) else - game.steps[game.who] = 1; + game.steps[game.who] = 1 } else { - game.steps[game.who] = block_max_steps(game.who); + game.steps[game.who] = block_max_steps(game.who) if (can_enter_besieged_port(where)) - game.castle.push(game.who); + game.castle.push(game.who) } - game.who = null; - end_draw_phase(); + game.who = null + end_draw_phase() }, next: function () { - end_draw_phase(); + end_draw_phase() }, } function end_draw_phase() { if (game.active === game.p1) { - game.active = game.p2; - start_draw_phase(); + game.active = game.p2 + start_draw_phase() } else { - end_game_turn(); + end_game_turn() } } function end_game_turn() { if (is_winter()) { - goto_winter_1(); + goto_winter_1() } else { if (check_sudden_death()) - return; - game.turn ++; - start_game_turn(); + return + game.turn ++ + start_game_turn() } } // WINTER CAMPAIGN & SUPPLY function goto_winter_1() { - log(""); - log("Start Winter of " + game.year); - log(""); + log("") + log("Start Winter of " + game.year) + log("") if (game.winter_campaign) - goto_winter_siege_attrition(); + goto_winter_siege_attrition() else - goto_winter_2(); + goto_winter_2() } function goto_winter_siege_attrition() { - log(game.active + " winter campaigned in " + game.winter_campaign + "."); - game.where = game.winter_campaign; + log(game.active + " winter campaigned in " + game.winter_campaign + ".") + game.where = game.winter_campaign - game.active = besieged_player(game.where); - game.state = 'winter_siege_attrition'; - game.attrition_list = []; + game.active = besieged_player(game.where) + game.state = 'winter_siege_attrition' + game.attrition_list = [] for (let b of BLOCKLIST) if (is_block_in_castle_in(b, game.where)) - game.attrition_list.push(b); + game.attrition_list.push(b) } function resume_winter_siege_attrition() { if (game.attrition_list.length === 0) { - delete game.attrition_list; + delete game.attrition_list if (!is_under_siege(game.where)) { - game.active = enemy(game.active); - log(game.where + " fell to siege attrition."); - goto_regroup(); + game.active = enemy(game.active) + log(game.where + " fell to siege attrition.") + goto_regroup() } else { - log("Siege continued."); - goto_winter_2(); + log("Siege continued.") + goto_winter_2() } } } @@ -3407,78 +3409,78 @@ function resume_winter_siege_attrition() { states.winter_siege_attrition = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Winter Siege Attrition: Waiting for " + game.active + "."; - view.prompt = "Winter Siege Attrition: Roll for siege attrition in " + game.where + "."; + return view.prompt = "Winter Siege Attrition: Waiting for " + game.active + "." + view.prompt = "Winter Siege Attrition: Roll for siege attrition in " + game.where + "." for (let b of game.attrition_list) gen_action(view, 'block', b) }, block: function (who) { - let target = (game.where === TYRE || game.where === TRIPOLI) ? 2 : 4; - let die = roll_d6(); + let target = (game.where === TYRE || game.where === TRIPOLI) ? 2 : 4 + let die = roll_d6() if (die <= target) { - log("Attrition roll " + DIE_HIT[die] + "."); - reduce_block(who); + log("Attrition roll " + DIE_HIT[die] + ".") + reduce_block(who) } else { - log("Attrition roll " + DIE_MISS[die] + "."); + log("Attrition roll " + DIE_MISS[die] + ".") } - remove_from_array(game.attrition_list, who); - resume_winter_siege_attrition(); + remove_from_array(game.attrition_list, who) + resume_winter_siege_attrition() } } function goto_winter_2() { - game.where = null; - eliminate_besieging_blocks(FRANKS); - eliminate_besieging_blocks(SARACENS); - lift_all_sieges(); + game.where = null + eliminate_besieging_blocks(FRANKS) + eliminate_besieging_blocks(SARACENS) + lift_all_sieges() if (check_sudden_death()) - return; + return if (game.year === 1192) - return goto_year_end(); - goto_winter_supply(); + return goto_year_end() + goto_winter_supply() } function eliminate_besieging_blocks(owner) { - game.summary = []; + game.summary = [] for (let b of BLOCKLIST) { if (block_owner(b) === owner) { - let where = game.location[b]; + let where = game.location[b] if (where === game.winter_campaign) - continue; + continue if (is_block_on_land(b) && is_under_siege(where)) if (block_owner(b) === besieging_player(where)) - disband(b); + disband(b) } } if (game.summary.length > 0) - print_summary(owner + " disbanded sieges:"); + print_summary(owner + " disbanded sieges:") else - game.summary = null; + game.summary = null } function need_winter_supply_check() { for (let town of TOWNLIST) { if (town === game.winter_campaign) - continue; + continue if (is_friendly_town(town) && !is_within_castle_limit(town)) - return true; + return true } - return false; + return false } function goto_winter_supply() { - game.active = FRANKS; + game.active = FRANKS if (need_winter_supply_check()) { - game.state = 'winter_supply'; - game.summary = []; + game.state = 'winter_supply' + game.summary = [] } else { - game.active = SARACENS; + game.active = SARACENS if (need_winter_supply_check()) { - game.state = 'winter_supply'; - game.summary = []; + game.state = 'winter_supply' + game.summary = [] } else { - game.active = FRANKS; - goto_winter_replacements(); + game.active = FRANKS + goto_winter_replacements() } } } @@ -3486,43 +3488,43 @@ function goto_winter_supply() { states.winter_supply = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Winter Supply: Waiting for " + game.active + "."; - gen_action_undo(view); - let okay_to_end = true; + return view.prompt = "Winter Supply: Waiting for " + game.active + "." + gen_action_undo(view) + let okay_to_end = true for (let b of BLOCKLIST) { if (block_owner(b) === game.active) { if (is_block_on_land(b)) { - let where = game.location[b]; + let where = game.location[b] if (where === game.winter_campaign) - continue; + continue if (!is_within_castle_limit(where)) { - gen_action(view, 'block', b); - okay_to_end = false; + gen_action(view, 'block', b) + okay_to_end = false } } } } if (okay_to_end) { - view.prompt = "Winter Supply: Disband excess blocks \u2014 done."; - gen_action(view, 'next'); + view.prompt = "Winter Supply: Disband excess blocks \u2014 done." + gen_action(view, 'next') } else { - view.prompt = "Winter Supply: Disband excess blocks."; + view.prompt = "Winter Supply: Disband excess blocks." } }, block: function (who) { - push_undo(); - disband(who); + push_undo() + disband(who) }, next: function () { - clear_undo(); + clear_undo() if (game.summary.length > 0) - print_summary(game.active + " disbanded:"); + print_summary(game.active + " disbanded:") if (game.active === FRANKS) { - game.active = SARACENS; - game.summary = []; + game.active = SARACENS + game.summary = [] } else { - game.active = FRANKS; - goto_winter_replacements(); + game.active = FRANKS + goto_winter_replacements() } }, undo: pop_undo @@ -3531,153 +3533,149 @@ states.winter_supply = { // WINTER REPLACEMENTS function goto_winter_replacements() { - game.rp = {}; + game.rp = {} for (let town of TOWNLIST) if (is_under_siege(town)) - game.rp[town] = 0; + game.rp[town] = 0 else - game.rp[town] = castle_limit(town); + game.rp[town] = castle_limit(town) - game.summary = []; - game.state = 'winter_replacements'; + game.summary = [] + game.state = 'winter_replacements' } function replacement_cost(where) { - let region = TOWNS[where].region; + let region = TOWNS[where].region if (KINGDOMS[region] === game.active) - return 1; - return 2; + return 1 + return 2 } states.winter_replacements = { prompt: function (view, current) { if (is_inactive_player(current)) - return view.prompt = "Winter Replacements: Waiting for " + game.active + "."; - view.prompt = "Winter Replacements: Distribute replacement points."; - gen_action_undo(view); - let okay_to_end = true; + return view.prompt = "Winter Replacements: Waiting for " + game.active + "." + view.prompt = "Winter Replacements: Distribute replacement points." + gen_action_undo(view) + let okay_to_end = true for (let b of BLOCKLIST) { if (block_owner(b) === game.active && is_block_on_land(b)) { - let where = game.location[b]; - let cost = replacement_cost(where); + let where = game.location[b] + let cost = replacement_cost(where) if (is_friendly_town(where) && game.rp[where] >= cost) { if (game.steps[b] < block_max_steps(b)) { - gen_action(view, 'block', b); - okay_to_end = false; + gen_action(view, 'block', b) + okay_to_end = false } } } } if (okay_to_end) { - view.prompt = "Winter Replacements: Distribute replacement points \u2014 done."; - gen_action(view, 'next'); + view.prompt = "Winter Replacements: Distribute replacement points \u2014 done." + gen_action(view, 'next') } else { - view.prompt = "Winter Replacements: Distribute replacement points."; + view.prompt = "Winter Replacements: Distribute replacement points." } }, block: function (who) { - push_undo(); - let where = game.location[who]; - let cost = replacement_cost(where); - game.summary.push([where]); - game.steps[who] ++; - game.rp[where] -= cost; + push_undo() + let where = game.location[who] + let cost = replacement_cost(where) + game.summary.push([where]) + game.steps[who] ++ + game.rp[where] -= cost }, next: function () { - clear_undo(); - end_winter_replacements(); + clear_undo() + end_winter_replacements() }, undo: pop_undo } function end_winter_replacements() { - print_summary(active_adjective() + " replacements:"); + print_summary(active_adjective() + " replacements:") if (game.active === FRANKS) { - game.active = SARACENS; - game.summary = []; + game.active = SARACENS + game.summary = [] } else { - goto_year_end(); + goto_year_end() } } function goto_year_end() { if (game.year === 1192) { - game.state = 'game_over'; - let f_vp = count_victory_points(FRANKS); - let s_vp = count_victory_points(SARACENS); + game.state = 'game_over' + let f_vp = count_victory_points(FRANKS) + let s_vp = count_victory_points(SARACENS) if (f_vp > s_vp) { - game.result = FRANKS; - game.victory = "Franks won!"; + game.result = FRANKS + game.victory = "Franks won!" } else if (f_vp < s_vp) { - game.victory = "Saracens won!"; - game.result = SARACENS; + game.victory = "Saracens won!" + game.result = SARACENS } else { - game.victory = "The game ended in a draw."; - game.result = null; + game.victory = "The game ended in a draw." + game.result = null } - log(""); - log(game.victory); - return; + log("") + log(game.victory) + return } // Return eliminated blocks to pool. for (let b of BLOCKLIST) if (game.location[b] === DEAD) - game.location[b] = block_pool(b); + game.location[b] = block_pool(b) - game.year ++; - start_year(); + game.year ++ + start_year() } // GAME OVER states.game_over = { prompt: function (view) { - view.prompt = game.victory; + view.prompt = game.victory } } // SETUP function setup_game() { - reset_blocks(); - game.year = 1187; - game.turn = 0; + reset_blocks() + game.year = 1187 + game.turn = 0 for (let b of BLOCKLIST) { if (block_owner(b) === FRANKS) { switch (block_type(b)) { case 'pilgrims': - deploy(b, block_pool(b)); - break; + deploy(b, block_pool(b)) + break case 'crusaders': - deploy(b, block_pool(b)); - break; + deploy(b, block_pool(b)) + break default: - deploy(b, block_home(b)); - break; + deploy(b, block_home(b)) + break } } if (block_owner(b) === SARACENS) { if (block_type(b) === 'emirs') - deploy(b, block_home(b)); + deploy(b, block_home(b)) if (block_type(b) === 'nomads') - deploy(b, block_pool(b)); + deploy(b, block_pool(b)) } if (block_owner(b) === ASSASSINS) { - deploy(b, block_home(b)); + deploy(b, block_home(b)) } } - goto_frank_deployment(); + goto_frank_deployment() } // VIEW function make_battle_view() { - let is_storming = game.storming.length > 0 && game.state !== 'declare_storm'; - let is_sallying = game.sallying.length > 0 && game.state !== 'declare_sally'; - let is_field_battle = game.is_field_battle; - let battle = { FR: [], FC: [], FF: [], SR: [], SC: [], SF: [], @@ -3691,18 +3689,18 @@ function make_battle_view() { show_castle: game.show_castle, show_field: game.show_field, town: game.where, - }; + } if (is_under_siege(game.where) && !is_contested_battle_field(game.where)) - battle.title = enemy(game.castle_owner) + " besiege " + game.where; + battle.title = enemy(game.castle_owner) + " besiege " + game.where else - battle.title = game.attacker[game.where] + " attack " + game.where; + battle.title = game.attacker[game.where] + " attack " + game.where if (game.combat_round === 0) - battle.title += " \u2014 Combat Deployment"; + battle.title += " \u2014 Combat Deployment" else - battle.title += " \u2014 Round " + game.combat_round + " of 3"; + battle.title += " \u2014 Round " + game.combat_round + " of 3" if (game.where === game.jihad) - battle.title += " \u2014 Jihad!"; + battle.title += " \u2014 Jihad!" function fill_cell(cell, owner, fn) { for (let b of BLOCKLIST) @@ -3710,16 +3708,16 @@ function make_battle_view() { cell.push(b) } - fill_cell(battle.FR, FRANKS, b => is_reserve(b)); - fill_cell(battle.FC, FRANKS, b => is_block_in_castle(b)); - fill_cell(battle.FF, FRANKS, b => is_block_in_field(b) && !game.storming.includes(b)); - fill_cell(battle.FF, SARACENS, b => is_block_in_field(b) && game.storming.includes(b)); - fill_cell(battle.SF, FRANKS, b => is_block_in_field(b) && game.storming.includes(b)); - fill_cell(battle.SF, SARACENS, b => is_block_in_field(b) && !game.storming.includes(b)); - fill_cell(battle.SC, SARACENS, b => is_block_in_castle(b)); - fill_cell(battle.SR, SARACENS, b => is_reserve(b)); + fill_cell(battle.FR, FRANKS, b => is_reserve(b)) + fill_cell(battle.FC, FRANKS, b => is_block_in_castle(b)) + fill_cell(battle.FF, FRANKS, b => is_block_in_field(b) && !game.storming.includes(b)) + fill_cell(battle.FF, SARACENS, b => is_block_in_field(b) && game.storming.includes(b)) + fill_cell(battle.SF, FRANKS, b => is_block_in_field(b) && game.storming.includes(b)) + fill_cell(battle.SF, SARACENS, b => is_block_in_field(b) && !game.storming.includes(b)) + fill_cell(battle.SC, SARACENS, b => is_block_in_castle(b)) + fill_cell(battle.SR, SARACENS, b => is_reserve(b)) - return battle; + return battle } exports.setup = function (seed, scenario, options) { @@ -3754,57 +3752,57 @@ exports.setup = function (seed, scenario, options) { game.rng = options.rng if (options && options.iron_bridge) { - game.iron_bridge = 1; - log("Iron Bridge:\nThe road between Antioch and Harim has a move limit of 3."); - log(""); + game.iron_bridge = 1 + log("Iron Bridge:\nThe road between Antioch and Harim has a move limit of 3.") + log("") } - setup_game(); - return game; + setup_game() + return game } exports.action = function (state, current, action, arg) { - game = state; - let S = states[game.state]; + game = state + let S = states[game.state] if (action in S) - S[action](arg, current); + S[action](arg, current) else - throw new Error("Invalid action: " + action); - return game; + throw new Error("Invalid action: " + action) + return game } exports.resign = function (state, current) { - game = state; + game = state if (game.state !== 'game_over') { - log(""); - log(current + " resigned."); - game.active = "None"; - game.state = 'game_over'; - game.victory = current + " resigned."; - game.result = enemy(current); + log("") + log(current + " resigned.") + game.active = "None" + game.state = 'game_over' + game.victory = current + " resigned." + game.result = enemy(current) } - return game; + return game } function make_siege_view() { - let list = {}; + let list = {} for (let t of TOWNLIST) if (is_under_siege(t)) - list[t] = besieging_player(t); - return list; + list[t] = besieging_player(t) + return list } function observer_hand() { - let hand = []; - hand.length = Math.max(game.s_hand.length, game.f_hand.length); - hand.fill(0); - return hand; + let hand = [] + hand.length = Math.max(game.s_hand.length, game.f_hand.length) + hand.fill(0) + return hand } -exports.is_checkpoint = (a, b) => a.turn !== b.turn; +exports.is_checkpoint = (a, b) => a.turn !== b.turn exports.view = function(state, current) { - game = state; + game = state let view = { log: game.log, @@ -3826,17 +3824,17 @@ exports.view = function(state, current) { battle: null, prompt: null, actions: null, - }; + } if (game.jihad && game.jihad !== game.p1) - view.jihad = game.jihad; + view.jihad = game.jihad if (game.winter_campaign && game.winter_campaign !== game.p1 && game.winter_campaign !== game.p2) - view.winter_campaign = game.winter_campaign; + view.winter_campaign = game.winter_campaign - states[game.state].prompt(view, current); + states[game.state].prompt(view, current) if (states[game.state].show_battle) - view.battle = make_battle_view(); + view.battle = make_battle_view() - return view; + return view } |