diff options
author | Tor Andersson <tor@ccxvii.net> | 2021-06-06 16:15:43 +0200 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2023-02-18 12:12:42 +0100 |
commit | 4befc7eb54e2f31709f0e29936570605abde8bbc (patch) | |
tree | c498652c67e33f312c3bfdf32657387a94a656db | |
parent | 8889442d2f01b78952626aa9917630840afd87f5 (diff) | |
download | shores-of-tripoli-4befc7eb54e2f31709f0e29936570605abde8bbc.tar.gz |
tripoli: Basic card play.
-rw-r--r-- | play.html | 3 | ||||
-rw-r--r-- | rules.js | 285 | ||||
-rw-r--r-- | ui.js | 20 |
3 files changed, 234 insertions, 74 deletions
@@ -18,7 +18,8 @@ .grid_role { background-color: ghostwhite; } .grid_log { background-color: ghostwhite; } .grid_top { background-color: silver; } -.grid_top.your_turn { background-color: orange; } +.grid_top.Tripolitania.your_turn { background-color: salmon; } +.grid_top.United_States.your_turn { background-color: skyblue; } .grid_top.disconnected { background-color: red; } .role_info { background-color: gainsboro; } .one .role_name { background-color: skyblue; } @@ -17,6 +17,23 @@ function get_space_id(name) { return SPACES.indexOf(name); } +function create_piece_list(n, name) { + let list = []; + for (let i = 1; i <= n; ++i) + list.push(get_piece_id(name + i)); + return list; +} + +const US_FRIGATES = create_piece_list(8, 'us_frigate_'); +const TR_FRIGATES = create_piece_list(2, 'tr_frigate_'); +const SE_FRIGATES = create_piece_list(2, 'se_frigate_'); +const US_GUNBOATS = create_piece_list(3, 'us_gunboat_'); +const TR_CORSAIRS = create_piece_list(9, 'tr_corsair_'); +const AL_CORSAIRS = create_piece_list(9, 'al_corsair_'); +const US_MARINES = create_piece_list(4, 'us_marine_'); +const AR_INFANTRY = create_piece_list(10, 'ar_infantry_'); +const TR_INFANTRY = create_piece_list(20, 'tr_infantry_'); + const ALEXANDRIA_HARBOR = get_space_id("Alexandria Harbor"); const ALGIERS_HARBOR = get_space_id("Algiers Harbor"); const ALGIERS_PATROL_ZONE = get_space_id("Algiers Patrol Zone"); @@ -40,8 +57,67 @@ const TRACK_1804 = get_space_id("1804"); const TRACK_1805 = get_space_id("1805"); const TRACK_1806 = get_space_id("1806"); -const US_CARD_NAMES = [ +const THOMAS_JEFFERSON = 1; +const SWEDISH_FRIGATES_ARRIVE = 2; +const HAMETS_ARMY_CREATED = 3; +const TREATY_OF_PEACE_AND_AMITY = 4; +const ASSAULT_ON_TRIPOLI = 5; +const NAVAL_MOVEMENT_1 = 6; +const NAVAL_MOVEMENT_2 = 7; +const NAVAL_MOVEMENT_3 = 8; +const NAVAL_MOVEMENT_4 = 9; +const EARLY_DEPLOYMENT = 10; +const A_SHOW_OF_FORCE = 11; +const TRIBUTE_PAID = 12; +const CONSTANTINOPLE_DEMANDS_TRIBUTE = 13; +const HAMET_RECRUITS_BEDOUINS = 14; +const BAINBRIDGE_SUPPLIES_INTEL = 15; +const CONGRESS_AUTHORIZES_ACTION = 16; +const CORSAIRS_CONFISCATED = 17; +const BURN_THE_PHILADELPHIA = 18; +const LAUNCH_THE_INTREPID = 19; +const GENERAL_EATON_ATTACKS_DERNE = 20; +const GENERAL_EATON_ATTACKS_BENGHAZI = 21; +const LIEUTENANT_STERETT_IN_PURSUIT = 22; +const PREBLES_BOYS_TAKE_AIM = 23; +const THE_DARING_STEPHEN_DECATUR = 24; +const SEND_IN_THE_MARINES = 25; +const LIEUTENANT_OBANNON_LEADS_THE_CHARGE = 26; +const MARINE_SHARPSHOOTERS = 27; + +const YUSUF_QARAMANLI = 28; +const MURAD_REIS_BREAKS_OUT = 29; +const CONSTANTINOPLE_SENDS_AID = 30; +const US_SUPPLIES_RUN_LOW = 31; +const ALGERINE_CORSAIRS_RAID_1 = 32; +const ALGERINE_CORSAIRS_RAID_2 = 33; +const MOROCCAN_CORSAIRS_RAID_1 = 34; +const MOROCCAN_CORSAIRS_RAID_2 = 35; +const TUNISIAN_CORSAIRS_RAID_1 = 36; +const TUNISIAN_CORSAIRS_RAID_2 = 37; +const TROOPS_TO_DERNE = 38; +const TROOPS_TO_BENGHAZI = 39; +const TROOPS_TO_TRIPOLI = 40; +const STORMS = 41; +const TRIPOLI_ATTACKS = 42; +const SWEDEN_PAYS_TRIBUTE = 43; +const TRIPOLI_ACQUIRES_CORSAIRS = 44; +const THE_PHILADELPHIA_RUNS_AGROUND = 45; +const ALGIERS_DECLARES_WAR = 46; +const MOROCCO_DECLARES_WAR = 47; +const TUNIS_DECLARES_WAR = 48; +const US_SIGNAL_BOOKS_OVERBOARD = 49; +const UNCHARTED_WATERS = 50; +const MERCHANT_SHIP_CONVERTED = 51; +const HAPPY_HUNTING = 52; +const THE_GUNS_OF_TRIPOLI = 53; +const MERCENARIES_DESERT = 54; + +const CARD_NAMES = [ + // No Card null, + + // United States Cards "Thomas Jefferson", "Swedish Frigates Arrive", "Hamet's Army Created", @@ -69,10 +145,8 @@ const US_CARD_NAMES = [ "Send in the Marines", "Lieutenant O'Bannon Leads the Charge", "Marine Sharpshooters", -]; -const TR_CARD_NAMES = [ - null, + // Tripolitan Cards "Yusuf Qaramanli", "Murad Reis Breaks Out", "Constantinople Sends Aid", @@ -102,41 +176,6 @@ const TR_CARD_NAMES = [ "Mercenaries Desert", ]; -const US_FRIGATES = [ - 'us_frigate_1', - 'us_frigate_2', - 'us_frigate_3', - 'us_frigate_4', - 'us_frigate_5', - 'us_frigate_6', - 'us_frigate_7', - 'us_frigate_8', -]; - -const TR_CORSAIRS = [ - 'tr_corsair_1', - 'tr_corsair_2', - 'tr_corsair_3', - 'tr_corsair_4', - 'tr_corsair_5', - 'tr_corsair_6', - 'tr_corsair_7', - 'tr_corsair_8', - 'tr_corsair_9', -]; - -const ALLIED_CORSAIRS = [ - 'al_corsair_1', - 'al_corsair_2', - 'al_corsair_3', - 'al_corsair_4', - 'al_corsair_5', - 'al_corsair_6', - 'al_corsair_7', - 'al_corsair_8', - 'al_corsair_9', -]; - const states = {}; let game = null; @@ -242,6 +281,42 @@ function count_pieces(list, where) { return n; } +function discard_card(player, card, reason = "") { + log(""); + log(game.active + " discards \"" + CARD_NAMES[card] + "\"" + reason + "."); + remove_from_array(player.hand, card); + player.discard.push(card); +} + +function play_card(player, card) { + log(""); + log(game.active + " plays \"" + CARD_NAMES[card] + "\"."); + remove_from_array(player.hand, card); + player.discard.push(card); +} + +function deploy(piece_name, space) { + game.location[get_piece_id(piece_name)] = space; +} + +function move_one_piece(list, from, to) { + for (let p of list) { + if (game.location[p] == from) { + game.location[p] = to; + return; + } + } + throw Error("no " + list + " to move from " + from); +} + +function move_all_pieces(list, from, to) { + for (let p of list) { + if (game.location[p] == from) { + game.location[p] = to; + } + } +} + function count_american_frigates(where) { return count_pieces(US_FRIGATES, where); } @@ -251,7 +326,7 @@ function count_tripolitan_corsairs(where) { } function count_allied_corsairs(where) { - return count_pieces(ALLIED_CORSAIRS, where); + return count_pieces(AL_CORSAIRS, where); } function can_play_thomas_jefferson() { @@ -283,23 +358,83 @@ function can_play_constantinople_sends_aid() { return game.tr.core.includes(3) && game.derne_captured; } +function can_build_gunboat_in_malta() { +console.log("count_pieces(US_GUNBOATS, UNITED_STATES_SUPPLY) = ", count_pieces(US_GUNBOATS, UNITED_STATES_SUPPLY)); +console.log(game.location); + return count_pieces(US_GUNBOATS, UNITED_STATES_SUPPLY) > 0; +} + +function can_move_up_to_two_frigates() { + return true; +} + +function can_build_corsair_in_tripoli() { + return count_pieces(TR_CORSAIRS, TRIPOLITAN_SUPPLY) > 0; +} + +function can_pirate_raid_from_tripoli() { + return count_pieces(TR_CORSAIRS, TRIPOLI_HARBOR) > 0; +} + function start_year() { game.active = US; game.state = 'american_play'; } +function end_american_play() { + game.active = TR; + game.state = 'tripolitan_play'; +} + +function end_tripolitan_play() { + game.active = US; + game.state = 'american_play'; +} + +function can_play_american_event(c) { + return false; +} + +function can_play_tripolitan_event(c) { + return false; +} + states.american_play = { prompt: function (view, current) { if (is_inactive_player(current)) return view.prompt = "American play."; view.prompt = "American play."; if (can_play_thomas_jefferson()) - gen_action(view, 'card_event', 'us1'); + gen_action(view, 'card_event', THOMAS_JEFFERSON); if (can_play_swedish_frigates_arrive()) - gen_action(view, 'card_event', 'us2'); + gen_action(view, 'card_event', SWEDISH_FRIGATES_ARRIVE); if (can_play_hamets_army_created()) - gen_action(view, 'card_event', 'us3'); + gen_action(view, 'card_event', HAMETS_ARMY_CREATED); + for (let c of game.us.hand) { + if (can_build_gunboat_in_malta()) + gen_action(view, 'card_build_gunboat', c); + if (can_move_up_to_two_frigates()) + gen_action(view, 'card_move_frigates', c); + if (can_play_american_event(c)) + gen_action(view, 'card_event', c); + } + if (game.us.hand.length == 0) + gen_action(view, 'pass'); + }, + card_build_gunboat: function (c) { + discard_card(game.us, c, " to build a gunboat in Malta"); + move_one_piece(US_GUNBOATS, UNITED_STATES_SUPPLY, MALTA_HARBOR); + end_american_play(); }, + card_move_frigates: function (c) { + discard_card(game.us, c, " to move up to two frigates"); + end_american_play(); + }, + pass: function () { + log(""); + log(game.active + " passes."); + end_american_play(); + } } states.tripolitan_play = { @@ -308,12 +443,36 @@ states.tripolitan_play = { return view.prompt = "Tripolitan play."; view.prompt = "Tripolitan play."; if (can_play_yusuf_qaramanli()) - gen_action(view, 'card_event', 'tr1'); + gen_action(view, 'card_event', YUSUF_QARAMANLI); if (can_play_murad_reis_breaks_out()) - gen_action(view, 'card_event', 'tr2'); + gen_action(view, 'card_event', MURAD_REIS_BREAKS_OUT); if (can_play_constantinople_sends_aid()) - gen_action(view, 'card_event', 'tr3'); + gen_action(view, 'card_event', CONSTANTINOPLE_SENDS_AID); + for (let c of game.tr.hand) { + if (can_build_corsair_in_tripoli()) + gen_action(view, 'card_build_corsair', c); + if (can_pirate_raid_from_tripoli()) + gen_action(view, 'card_pirate_raid', c); + if (can_play_tripolitan_event(c)) + gen_action(view, 'card_event', c); + } + if (game.tr.hand.length == 0) + gen_action(view, 'pass'); + }, + card_build_corsair: function (c) { + discard_card(game.tr, c, " to build a Tripolitan corsair in Tripoli"); + move_one_piece(TR_CORSAIRS, TRIPOLITAN_SUPPLY, TRIPOLI_HARBOR); + end_tripolitan_play(); + }, + card_pirate_raid: function (c) { + discard_card(game.tr, c, " to Pirate Raid with the corsairs from Tripoli"); + end_tripolitan_play(); }, + pass: function () { + log(""); + log(game.active + " passes."); + end_tripolitan_play(); + } } states.game_over = { @@ -322,10 +481,6 @@ states.game_over = { }, } -function deploy(piece_name, space) { - game.location[get_piece_id(piece_name)] = space; -} - exports.setup = function (scenario, players) { if (players.length != 2) throw new Error("Invalid player count: " + players.length); @@ -336,13 +491,13 @@ exports.setup = function (scenario, players) { log: [], location: [], us: { - core: [ 1, 2, 3 ], + core: [], hand: [], deck: [], discard: [], }, tr: { - core: [ 1, 2, 3 ], + core: [], hand: [], deck: [], discard: [], @@ -351,10 +506,19 @@ exports.setup = function (scenario, players) { derne_captured: 0, }; + game.tr.core.push(YUSUF_QARAMANLI); + game.tr.core.push(MURAD_REIS_BREAKS_OUT); + game.tr.core.push(CONSTANTINOPLE_SENDS_AID); + + game.us.core.push(THOMAS_JEFFERSON); + game.us.core.push(SWEDISH_FRIGATES_ARRIVE); + game.us.core.push(HAMETS_ARMY_CREATED); + for (let i = 4; i <= 27; ++i) { game.us.deck.push(i); - game.tr.deck.push(i); + game.tr.deck.push(i+27); } + game.us.hand = deal_cards(game.us.deck, 6); game.tr.hand = deal_cards(game.tr.deck, 6); @@ -367,9 +531,6 @@ exports.setup = function (scenario, players) { deploy("us_frigate_7", UNITED_STATES_SUPPLY); deploy("us_frigate_8", UNITED_STATES_SUPPLY); -//for (let i = 1; i <= 8; ++i) -//deploy("us_frigate_" + i, UNITED_STATES_SUPPLY); - deploy("us_gunboat_1", UNITED_STATES_SUPPLY); deploy("us_gunboat_2", UNITED_STATES_SUPPLY); deploy("us_gunboat_3", UNITED_STATES_SUPPLY); @@ -398,9 +559,6 @@ exports.setup = function (scenario, players) { deploy("tr_corsair_8", TRIPOLITAN_SUPPLY); deploy("tr_corsair_9", TRIPOLITAN_SUPPLY); -//for (let i = 1; i <= 9; ++i) -//deploy("tr_corsair_" + i, TRIPOLITAN_SUPPLY); - for (let i = 1; i <= 9; ++i) deploy("al_corsair_" + i, TRIPOLITAN_SUPPLY); @@ -413,7 +571,6 @@ exports.setup = function (scenario, players) { deploy("tr_infantry_7", DERNE_HARBOR); deploy("tr_infantry_8", DERNE_HARBOR); for (let i = 9; i <= 20; ++i) -//for (let i = 1; i <= 20; ++i) deploy("tr_infantry_" + i, TRIPOLITAN_SUPPLY); start_year(); @@ -459,14 +616,14 @@ exports.view = function(state, current) { prompt: null, actions: null, tr: { - core: game.tr.core.map(x => 'tr' + x), + core: game.tr.core, deck: game.tr.deck.length, discard: game.tr.discard.length, hand: game.tr.hand.length, coins: game.tr.coins, }, us: { - core: game.us.core.map(x => 'us' + x), + core: game.us.core, deck: game.us.deck.length, discard: game.us.discard.length, hand: game.us.hand.length, @@ -476,9 +633,9 @@ exports.view = function(state, current) { states[game.state].prompt(view, current); if (current == TR) - view.hand = game.tr.hand.map(x => 'tr' + x); + view.hand = game.tr.hand; else if (current == US) - view.hand = game.us.hand.map(x => 'us' + x); + view.hand = game.us.hand; else view.hand = []; @@ -57,6 +57,9 @@ function on_blur(evt) { document.getElementById("status").textContent = ""; } +function on_pass() { if (game.actions) { send_action('pass', null); } } +function on_undo() { if (game.actions) { send_action('undo', null); } } + function build_map() { let i = 0; for (let space of SPACES) { @@ -80,15 +83,13 @@ function build_map() { } } for (i = 1; i <= 27; ++i) { - let e = ui.cards['us'+i] = document.getElementById("us_card_"+i); + let e = ui.cards[i] = document.getElementById("us_card_"+i); e.addEventListener("click", on_card); - e.deck = 'us'; e.card = i; } - for (i = 1; i <= 27; ++i) { - let e = ui.cards['tr'+i] = document.getElementById("tr_card_"+i); + for (i = 28; i <= 54; ++i) { + let e = ui.cards[i] = document.getElementById("tr_card_"+(i-27)); e.addEventListener("click", on_card); - e.deck = 'tr'; e.card = i; } } @@ -104,18 +105,19 @@ function update_cards() { document.getElementById("us_card_deck").textContent = game.us.deck; document.getElementById("tr_card_deck").textContent = game.tr.deck; for (let i = 1; i <= 3; ++i) { - update_card('us'+i, game.us.core.includes('us'+i)); - update_card('tr'+i, game.tr.core.includes('tr'+i)); + update_card(i, game.us.core.includes(i)); + update_card(i+27, game.tr.core.includes(i+27)); } for (let i = 4; i <= 27; ++i) { - update_card('us'+i, game.hand.includes('us'+i)); - update_card('tr'+i, game.hand.includes('tr'+i)); + update_card(i, game.hand.includes(i)); + update_card(i+27, game.hand.includes(i+27)); } } /* MAP AND PIECE LAYOUT */ function on_update() { + show_action_button("#button_pass", "pass"); update_year_marker(game.year); update_season_marker(game.season); update_pieces(game.location); |