diff options
author | Tor Andersson <tor@ccxvii.net> | 2022-10-02 22:19:25 +0200 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2022-11-16 19:12:55 +0100 |
commit | e269954c8a936600f3d3d7fdba156b046e586df5 (patch) | |
tree | 7fb42e092e92ae4760f64b143e70d6c6c706135f | |
parent | 168b3f168bfb92336567a30c3e2a6fd961890abb (diff) | |
download | richard-iii-e269954c8a936600f3d3d7fdba156b046e586df5.tar.gz |
Nobody and nowhere.
-rw-r--r-- | play.js | 31 | ||||
-rw-r--r-- | rules.js | 141 |
2 files changed, 85 insertions, 87 deletions
@@ -9,6 +9,9 @@ const POOL = "Pool"; const DEAD = "Dead"; const MINOR = "Minor"; +const NOBODY = -1 +const NOWHERE = 0 + const KING_TEXT = "\u2756"; const PRETENDER_TEXT = ""; @@ -128,7 +131,7 @@ const STEP_TEXT = [ 0, "I", "II", "III", "IIII" ]; const HEIR_TEXT = [ 0, '\u00b9', '\u00b2', '\u00b3', '\u2074', '\u2075' ]; function block_name(who) { - if (!who) return "Nobody"; + if (who === NOBODY) return "Nobody"; let name = BLOCKS[who].name; let long_name = LONG_NAME[name]; return long_name ? long_name : name; @@ -136,9 +139,9 @@ function block_name(who) { function block_owner(who) { if (who === REBEL) { - if (view.pretender) + if (view.pretender !== NOBODY) return BLOCKS[view.pretender].owner; - if (view.king) + if (view.king !== NOBODY) return ENEMY[BLOCKS[view.king].owner]; return YORK; } @@ -454,7 +457,7 @@ function hide_block(element) { } function is_dead(who) { - return view.location[who] === null; + return view.location[who] === NOWHERE; } function is_perma_dead(who) { @@ -493,14 +496,14 @@ function update_map() { let known = is_known_block(b); // perma-dead nobles - if (area === null && is_perma_dead(b)) { + if (area === NOWHERE && is_perma_dead(b)) { area = DEAD; moved = " moved"; known = 1; steps = ""; } - if (area !== null) { + if (area !== NOWHERE) { if (known) { element.classList = info.owner + " known block" + image + steps + moved; } else { @@ -528,16 +531,16 @@ function update_map() { } } - for (let where in AREAS) { - if (ui.areas[where]) { - ui.areas[where].classList.remove('highlight'); - ui.areas[where].classList.remove('where'); + for (let area in AREAS) { + if (ui.areas[area]) { + ui.areas[area].classList.remove('highlight'); + ui.areas[area].classList.remove('where'); } } if (view.actions && view.actions.area) - for (let where of view.actions.area) - ui.areas[where].classList.add('highlight'); - if (view.where) + for (let area of view.actions.area) + ui.areas[area].classList.add('highlight'); + if (view.where !== NOWHERE) ui.areas[view.where].classList.add('where'); for (let b in BLOCKS) { @@ -548,7 +551,7 @@ function update_map() { if (view.actions && view.actions.block) for (let b of view.actions.block) ui.blocks[b].classList.add('highlight'); - if (view.who) + if (view.who !== NOBODY) ui.blocks[view.who].classList.add('selected'); } } @@ -29,6 +29,9 @@ const BOTH = "Both" const POOL = "Pool" const MINOR = "Minor" +const NOBODY = -1 +const NOWHERE = 0 + // serif cirled numbers const DIE_HIT = [ 0, '\u2776', '\u2777', '\u2778', '\u2779', '\u277A', '\u277B' ] const DIE_MISS = [ 0, '\u2460', '\u2461', '\u2462', '\u2463', '\u2464', '\u2465' ] @@ -195,8 +198,8 @@ function is_royal_heir(who) { function is_dead(who) { if (who in BLOCKS) - return !game.location[who] - return !game.location[who+"/L"] && !game.location[who+"/Y"] + return game.location[who] === NOWHERE + return game.location[who+"/L"] === NOWHERE && game.location[who+"/Y"] === NOWHERE } function is_shield_area_for(where, who, combat) { @@ -261,7 +264,7 @@ function is_shield_area_for(where, who, combat) { function is_at_home(who) { let where = game.location[who] - if (!where || where === MINOR || where === POOL) + if (where === NOWHERE || where === MINOR || where === POOL) return true if (is_pretender_heir(who)) return is_exile_area(where) @@ -331,14 +334,13 @@ function go_home_if_possible(who) { function is_on_map_not_in_exile_or_man(who) { let where = game.location[who] - return where && where !== MINOR && - where !== POOL && + return where !== NOWHERE && where !== MINOR && where !== POOL && where !== "Isle of Man" && !is_exile_area(where) } function is_land_area(where) { - return where && where !== MINOR && where !== POOL && !is_sea_area(where) + return where !== NOWHERE && where !== MINOR && where !== POOL && !is_sea_area(where) } function is_area_friendly_to(where, owner) { @@ -391,9 +393,9 @@ function block_home(who) { function block_owner(who) { if (who === REBEL) { - if (game.pretender) + if (game.pretender !== NOBODY) return block_owner(game.pretender) - else if (game.king) + else if (game.king !== NOBODY) return ENEMY[block_owner(game.king)] else return YORK // whatever... they're both dead @@ -460,7 +462,7 @@ function is_neville(who) { } function block_loyalty(source, target) { - let source_name = source ? block_name(source) : "Event" + let source_name = source !== NOBODY ? block_name(source) : "Event" if (source_name === "Warwick") { let target_name = block_name(target) if (target_name === "Kent" || target_name === "Salisbury") @@ -481,11 +483,11 @@ function can_defect(source, target) { function can_attempt_treason_event() { if (game.treason === game.attacker[game.where]) { for (let b of BLOCKLIST) - if (is_defender(b) && can_defect(null, b)) + if (is_defender(b) && can_defect(NOBODY, b)) return true } else { for (let b of BLOCKLIST) - if (is_attacker(b) && can_defect(null, b)) + if (is_attacker(b) && can_defect(NOBODY, b)) return true } return false @@ -523,7 +525,7 @@ function can_activate(who) { } function is_area_on_map(location) { - return location && location !== MINOR && location !== POOL + return location !== NOWHERE && location !== MINOR && location !== POOL } function is_block_on_map(b) { @@ -726,7 +728,7 @@ function can_block_sea_move_to(who, from, to) { function can_block_sea_move(who) { if (can_activate(who)) { let from = game.location[who] - if (from) { + if (from !== NOWHERE) { if (is_pinned(who, from)) return false for (let to of AREAS[from].exits) @@ -796,7 +798,7 @@ function can_block_land_move_to(who, from, to) { function can_block_land_move(who) { if (can_activate(who)) { let from = game.location[who] - if (from) { + if (from !== NOWHERE) { if (is_pinned(who, from)) return false for (let to of AREAS[from].exits) @@ -909,7 +911,7 @@ function swap_blocks(a) { let b = BLOCKS[a].enemy game.location[b] = game.location[a] game.steps[b] = game.steps[a] - game.location[a] = null + game.location[a] = NOWHERE game.steps[a] = block_max_steps(a) return b } @@ -937,17 +939,17 @@ function eliminate_block(who) { log(block_name(who) + " was eliminated.") game.flash += " " + block_name(who) + " was eliminated." if (who === "Exeter/Y") { - game.location[who] = null + game.location[who] = NOWHERE ++game.killed_heirs[LANCASTER] return check_instant_victory() } if (who === "Clarence/L") { - game.location[who] = null + game.location[who] = NOWHERE ++game.killed_heirs[YORK] return check_instant_victory() } if (is_heir(who)) { - game.location[who] = null + game.location[who] = NOWHERE ++game.killed_heirs[block_owner(who)] if (who === game.pretender) game.pretender = find_senior_heir(block_owner(game.pretender)) @@ -955,7 +957,7 @@ function eliminate_block(who) { return check_instant_victory() } if (is_rose_noble(who) || is_neville(who)) { - game.location[who] = null + game.location[who] = NOWHERE return } if (is_mercenary(who)) { @@ -1099,7 +1101,7 @@ function deploy_york(name, where) { function reset_blocks() { for (let b of BLOCKLIST) { - game.location[b] = null + game.location[b] = NOWHERE game.steps[b] = block_max_steps(b) } } @@ -1601,7 +1603,7 @@ states.muster_who = { game.state = 'muster_move_1' }, end_action_phase: function () { - game.where = null + game.where = NOWHERE clear_undo() print_turn_log(game.active + " mustered:") end_player_turn() @@ -1630,7 +1632,7 @@ states.muster_move_1 = { if (to === game.where) { log_move_end() set_add(game.moved, game.who) - game.who = null + game.who = NOBODY game.state = 'muster_who' } else { game.state = 'muster_move_2' @@ -1653,7 +1655,7 @@ states.muster_move_2 = { log_move_end() move_block(game.who, game.location[game.who], to) set_add(game.moved, game.who) - game.who = null + game.who = NOBODY game.state = 'muster_who' }, undo: pop_undo, @@ -1741,7 +1743,7 @@ states.action_phase = { } if (can_block_sea_move(b)) { if (game.moves === 0) { - if (game.move_port[game.location[b]]) + if (game.move_port[game.location[b]] !== undefined) gen_action(view, 'block', b) } else { gen_action(view, 'block', b) @@ -1757,7 +1759,7 @@ states.action_phase = { game.state = 'recruit_where' } else { game.distance = 0 - game.last_from = null + game.last_from = NOWHERE game.state = 'move_to' } }, @@ -1932,15 +1934,15 @@ function end_move() { } set_add(game.moved, game.who) } - game.last_from = null + game.last_from = NOWHERE end_action() } function end_action() { free_henry_vi() - game.who = null + game.who = NOBODY game.distance = 0 - game.origin = null + game.origin = NOWHERE game.state = 'action_phase' } @@ -1990,7 +1992,7 @@ function start_battle(where) { function resume_battle() { if (game.result) return goto_game_over() - game.who = null + game.who = NOBODY game.state = 'battle_round' pump_battle_round() } @@ -2017,12 +2019,12 @@ states.treason_event = { gen_action(view, 'pass') for (let b of BLOCKLIST) { if (game.active === game.attacker[game.where]) { - if (is_defender(b) && can_defect(null, b)) { + if (is_defender(b) && can_defect(NOBODY, b)) { gen_action(view, 'battle_treachery', b) gen_action(view, 'block', b) } } else { - if (is_attacker(b) && can_defect(null, b)) { + if (is_attacker(b) && can_defect(NOBODY, b)) { gen_action(view, 'battle_treachery', b) gen_action(view, 'block', b) } @@ -2031,13 +2033,13 @@ states.treason_event = { }, battle_treachery: function (target) { delete game.treason - attempt_treachery(null, target) + attempt_treachery(NOBODY, target) game.state = 'battle_round' start_battle_round() }, block: function (target) { delete game.treason - attempt_treachery(null, target) + attempt_treachery(NOBODY, target) game.state = 'battle_round' start_battle_round() }, @@ -2221,7 +2223,7 @@ function fire_with_block(b) { } function attempt_treachery(source, target) { - if (source) { + if (source !== NOBODY) { let once = treachery_tag(source) set_add(game.treachery, once) set_add(game.moved, source) @@ -2238,7 +2240,7 @@ function attempt_treachery(source, target) { rolls.push(DIE_HIT[die]) } } - if (source) + if (source !== NOBODY) game.flash = block_name(source) + " treachery " + rolls.join(" ") else game.flash = "Treason event " + rolls.join(" ") @@ -2282,40 +2284,40 @@ function can_block_fire(who) { } function find_minor_heir(owner) { - let candidate = null + let candidate = NOBODY for (let b of BLOCKLIST) { if (block_owner(b) === owner && block_type(b) === 'heir' && game.location[b] === MINOR) - if (!candidate || BLOCKS[b].heir < BLOCKS[candidate].heir) + if (candidate === NOBODY || BLOCKS[b].heir < BLOCKS[candidate].heir) candidate = b } return candidate } function find_senior_heir(owner) { - let candidate = null + let candidate = NOBODY for (let b of BLOCKLIST) if (block_owner(b) === owner && block_type(b) === 'heir' && !is_dead(b)) - if (!candidate || BLOCKS[b].heir < BLOCKS[candidate].heir) + if (candidate === NOBODY || BLOCKS[b].heir < BLOCKS[candidate].heir) candidate = b return candidate } function find_next_king(owner) { - let candidate = null + let candidate = NOBODY for (let b of BLOCKLIST) - if (block_owner(b) === owner && block_type(b) === 'heir' && game.location[b]) - if (!candidate || BLOCKS[b].heir < BLOCKS[candidate].heir) + if (block_owner(b) === owner && block_type(b) === 'heir' && game.location[b] !== NOWHERE) + if (candidate === NOBODY || BLOCKS[b].heir < BLOCKS[candidate].heir) candidate = b return candidate } function find_senior_heir_in_area(owner, where) { - let candidate = null + let candidate = NOBODY for (let b of BLOCKLIST) { if (block_owner(b) === owner && block_type(b) === 'heir' && game.location[b] === where) { if (is_battle_reserve(b)) continue - if (!candidate || BLOCKS[b].heir < BLOCKS[candidate].heir) + if (candidate === NOBODY || BLOCKS[b].heir < BLOCKS[candidate].heir) candidate = b } } @@ -2328,13 +2330,13 @@ function is_senior_royal_heir_in(who, where) { function can_heir_charge() { let heir = find_senior_heir_in_area(game.active, game.where) - if (heir && !set_has(game.moved, heir)) { + if (heir !== NOBODY && !set_has(game.moved, heir)) { if (is_attacker(heir)) - return game.battle_round < 4 ? heir : null + return game.battle_round < 4 ? heir : NOBODY if (is_defender(heir)) return heir } - return null + return NOBODY } states.battle_round = { @@ -2367,7 +2369,7 @@ states.battle_round = { } let heir = can_heir_charge() - if (heir && set_has(game.battle_list, heir)) + if (heir !== NOBODY && set_has(game.battle_list, heir)) gen_action(view, 'battle_charge', heir) if (can_attempt_treachery(game.king)) gen_action(view, 'battle_treachery', game.king) @@ -2647,7 +2649,7 @@ states.regroup = { game.state = 'regroup_to' }, end_regroup: function () { - game.where = null + game.where = NOWHERE clear_undo() print_turn_log(game.active + " regrouped:") goto_battle_phase() @@ -2686,7 +2688,7 @@ states.regroup_to = { } else { game.turn_log.push([game.where, to]) move_block(game.who, game.where, to) - game.who = null + game.who = NOBODY game.state = 'regroup' } }, @@ -2709,7 +2711,7 @@ states.sea_regroup_to = { log_move_continue(to) log_move_end() game.location[game.who] = to - game.who = null + game.who = NOBODY game.state = 'regroup' }, undo: pop_undo, @@ -2720,7 +2722,7 @@ states.sea_regroup_to = { function goto_supply_phase() { set_clear(game.moved) - if (!game.location[game.king]) { + if (game.location[game.king] === NOWHERE) { game.king = find_next_king(block_owner(game.king)) log("The King is dead; long live the king!") if (game.location[game.king] === MINOR) @@ -2753,13 +2755,13 @@ states.execute_clarence = { execute_clarence: function () { logp("executed Clarence.") eliminate_block("Clarence/L") - game.who = null + game.who = NOBODY if (game.result) return goto_game_over() goto_execute_exeter() }, pass: function () { - game.who = null + game.who = NOBODY goto_execute_exeter() } } @@ -2785,13 +2787,13 @@ states.execute_exeter = { execute_exeter: function () { logp("executed Exeter.") eliminate_block("Exeter/Y") - game.who = null + game.who = NOBODY if (game.result) return goto_game_over() goto_enter_pretender_heir() }, pass: function () { - game.who = null + game.who = NOBODY goto_enter_pretender_heir() } } @@ -2801,7 +2803,7 @@ states.execute_exeter = { function goto_enter_pretender_heir() { game.active = block_owner(game.pretender) let n = game.killed_heirs[game.active] - if (n > 0 && (game.who = find_minor_heir(game.active))) + if (n > 0 && (game.who = find_minor_heir(game.active)) !== NOBODY) game.state = 'enter_pretender_heir' else goto_supply_limits_pretender() @@ -2816,15 +2818,12 @@ states.enter_pretender_heir = { if (is_pretender_exile_area(where)) gen_action(view, 'area', where) }, - block: function () { - game.who = null - }, area: function (to) { logbr() log(block_name(game.who) + " came of age in " + to + ".") --game.killed_heirs[game.active] game.location[game.who] = to - game.who = null + game.who = NOBODY goto_enter_pretender_heir() }, } @@ -2878,7 +2877,7 @@ states.supply_limits_pretender = { function goto_enter_royal_heir() { game.active = block_owner(game.king) let n = game.killed_heirs[game.active] - if (n > 0 && (game.who = find_minor_heir(game.active))) + if (n > 0 && (game.who = find_minor_heir(game.active)) !== NOBODY) game.state = 'enter_royal_heir' else goto_supply_limits_king() @@ -2899,19 +2898,16 @@ states.enter_royal_heir = { if (!can_enter) gen_action(view, 'pass') }, - block: function () { - game.who = null - }, area: function (to) { logbr() log(block_name(game.who) + " came of age in " + to + ".") --game.killed_heirs[game.active] game.location[game.who] = to - game.who = null + game.who = NOBODY goto_enter_royal_heir() }, pass: function () { - game.who = null + game.who = NOBODY goto_supply_limits_king() } } @@ -3142,7 +3138,7 @@ states.pretender_goes_home_to = { game.turn_log.push([block_name(game.who), to]) // TODO: "Home"? set_add(game.moved, game.who) game.location[game.who] = to - game.who = null + game.who = NOBODY game.state = 'pretender_goes_home' }, block: pop_undo, @@ -3267,7 +3263,7 @@ states.king_goes_home_to = { game.turn_log.push([block_name(game.who), to]) // TODO: "Home"? set_add(game.moved, game.who) game.location[game.who] = to - game.who = null + game.who = NOBODY game.state = 'king_goes_home' }, block: pop_undo, @@ -3371,8 +3367,8 @@ exports.setup = function (seed, scenario, options) { active: null, moves: 0, - who: null, - where: null, + who: NOBODY, + where: NOWHERE, show_cards: false, killed_heirs: { Lancaster: 0, York: 0 }, @@ -3451,14 +3447,13 @@ exports.view = function(state, current) { l_card: (game.show_cards || current === LANCASTER) ? game.l_card : 0, y_card: (game.show_cards || current === YORK) ? game.y_card : 0, hand: (current === LANCASTER) ? game.l_hand : (current === YORK) ? game.y_hand : observer_hand(), - who: (game.active === current) ? game.who : null, + who: (game.active === current) ? game.who : NOBODY, where: game.where, location: game.location, steps: game.steps, moved: game.moved, battle: null, prompt: null, - actions: null, } states[game.state].prompt(view, current) |