summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2021-06-06 16:15:43 +0200
committerTor Andersson <tor@ccxvii.net>2023-02-18 12:12:42 +0100
commit4befc7eb54e2f31709f0e29936570605abde8bbc (patch)
treec498652c67e33f312c3bfdf32657387a94a656db
parent8889442d2f01b78952626aa9917630840afd87f5 (diff)
downloadshores-of-tripoli-4befc7eb54e2f31709f0e29936570605abde8bbc.tar.gz
tripoli: Basic card play.
-rw-r--r--play.html3
-rw-r--r--rules.js285
-rw-r--r--ui.js20
3 files changed, 234 insertions, 74 deletions
diff --git a/play.html b/play.html
index 0d0400a..11b74e7 100644
--- a/play.html
+++ b/play.html
@@ -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; }
diff --git a/rules.js b/rules.js
index f7c23f4..d43f1b2 100644
--- a/rules.js
+++ b/rules.js
@@ -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 = [];
diff --git a/ui.js b/ui.js
index 6813885..cd711d8 100644
--- a/ui.js
+++ b/ui.js
@@ -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);