summaryrefslogtreecommitdiff
path: root/rules.js
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2021-06-07 10:51:32 +0200
committerTor Andersson <tor@ccxvii.net>2023-02-18 12:12:42 +0100
commit068eb263197335f0abde0ab38bc3780fec40c109 (patch)
tree7a24229e828cd143bea79663200d1ddd6341f421 /rules.js
parent25c63103c6d93f793b8c95ed713c27912ae57551 (diff)
downloadshores-of-tripoli-068eb263197335f0abde0ab38bc3780fec40c109.tar.gz
tripoli: Start events.
Diffstat (limited to 'rules.js')
-rw-r--r--rules.js637
1 files changed, 483 insertions, 154 deletions
diff --git a/rules.js b/rules.js
index b984fb7..ba90894 100644
--- a/rules.js
+++ b/rules.js
@@ -1,4 +1,10 @@
"use strict";
+// Tribute Paid
+
+// RULES QUESTIONS:
+// A Show of Force -- can play with fewer than 3 available frigates?
+
+// TODO: Open Sea zone during piracy
// Battle Card timing:
@@ -51,6 +57,11 @@ 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 SPRING = 0;
+const SUMMER = 1;
+const FALL = 2;
+const WINTER = 3;
+
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");
@@ -74,7 +85,7 @@ const TRACK_1804 = get_space_id("1804");
const TRACK_1805 = get_space_id("1805");
const TRACK_1806 = get_space_id("1806");
-const TRACK_YEAR = {
+const YEAR_TURN_TRACK = {
1801: TRACK_1801,
1802: TRACK_1802,
1803: TRACK_1803,
@@ -110,6 +121,14 @@ const BATTLE_SPACES = [
TUNIS_HARBOR,
];
+const PATROL_ZONES = [
+ ALGIERS_PATROL_ZONE,
+ GIBRALTAR_PATROL_ZONE,
+ TANGIER_PATROL_ZONE,
+ TRIPOLI_PATROL_ZONE,
+ TUNIS_PATROL_ZONE,
+];
+
const THOMAS_JEFFERSON = 1;
const SWEDISH_FRIGATES_ARRIVE = 2;
const HAMETS_ARMY_CREATED = 3;
@@ -231,42 +250,38 @@ const CARD_NAMES = [
"Mercenaries Desert",
];
-function should_remove_after_play(card) {
- switch (card) {
- case THOMAS_JEFFERSON:
- case SWEDISH_FRIGATES_ARRIVE:
- case HAMETS_ARMY_CREATED:
- case CONGRESS_AUTHORIZES_ACTION:
- case CORSAIRS_CONFISCATED:
- case BURN_THE_PHILADELPHIA:
- case LAUNCH_THE_INTREPID:
- case GENERAL_EATON_ATTACKS_DERNE:
- case GENERAL_EATON_ATTACKS_BENGHAZI:
- case LIEUTENANT_STERETT_IN_PURSUIT:
- case PREBLES_BOYS_TAKE_AIM:
- case THE_DARING_STEPHEN_DECATUR:
- case SEND_IN_THE_MARINES:
- case LIEUTENANT_OBANNON_LEADS_THE_CHARGE:
- case MARINE_SHARPSHOOTERS:
- case YUSUF_QARAMANLI:
- case MURAD_REIS_BREAKS_OUT:
- case CONSTANTINOPLE_SENDS_AID:
- case SWEDEN_PAYS_TRIBUTE:
- case TRIPOLI_ACQUIRES_CORSAIRS:
- case THE_PHILADELPHIA_RUNS_AGROUND:
- case ALGIERS_DECLARES_WAR:
- case MOROCCO_DECLARES_WAR:
- case TUNIS_DECLARES_WAR:
- case US_SIGNAL_BOOKS_OVERBOARD:
- case UNCHARTED_WATERS:
- case MERCHANT_SHIP_CONVERTED:
- case HAPPY_HUNTING:
- case THE_GUNS_OF_TRIPOLI:
- case MERCENARIES_DESERT:
- return true;
- }
- return false;
-}
+const REMOVE_AFTER_PLAY = [
+ THOMAS_JEFFERSON,
+ SWEDISH_FRIGATES_ARRIVE,
+ HAMETS_ARMY_CREATED,
+ CONGRESS_AUTHORIZES_ACTION,
+ CORSAIRS_CONFISCATED,
+ BURN_THE_PHILADELPHIA,
+ LAUNCH_THE_INTREPID,
+ GENERAL_EATON_ATTACKS_DERNE,
+ GENERAL_EATON_ATTACKS_BENGHAZI,
+ LIEUTENANT_STERETT_IN_PURSUIT,
+ PREBLES_BOYS_TAKE_AIM,
+ THE_DARING_STEPHEN_DECATUR,
+ SEND_IN_THE_MARINES,
+ LIEUTENANT_OBANNON_LEADS_THE_CHARGE,
+ MARINE_SHARPSHOOTERS,
+ YUSUF_QARAMANLI,
+ MURAD_REIS_BREAKS_OUT,
+ CONSTANTINOPLE_SENDS_AID,
+ SWEDEN_PAYS_TRIBUTE,
+ TRIPOLI_ACQUIRES_CORSAIRS,
+ THE_PHILADELPHIA_RUNS_AGROUND,
+ ALGIERS_DECLARES_WAR,
+ MOROCCO_DECLARES_WAR,
+ TUNIS_DECLARES_WAR,
+ US_SIGNAL_BOOKS_OVERBOARD,
+ UNCHARTED_WATERS,
+ MERCHANT_SHIP_CONVERTED,
+ HAPPY_HUNTING,
+ THE_GUNS_OF_TRIPOLI,
+ MERCENARIES_DESERT,
+];
const states = {};
@@ -388,8 +403,9 @@ function discard_card(player, card, reason = "") {
function play_card(player, card) {
log("");
log(game.active + " plays \"" + CARD_NAMES[card] + "\".");
+ remove_from_array(player.core, card);
remove_from_array(player.hand, card);
- if (!should_remove_after_play(card))
+ if (!REMOVE_AFTER_PLAY.includes(card))
player.discard.push(card);
game.active_card = card;
}
@@ -416,12 +432,23 @@ function move_all_pieces(list, from, to) {
}
}
-function fire(what, n_dice) {
+function fire_2(what, n) {
+ let hits = 0;
+ for (let i = 0; i < n; ++i) {
+ let a = roll_d6();
+ let b = roll_d6();
+ if (a == 6) ++hits;
+ if (b == 6) ++hits;
+ log(what + " fires " + a + ", " + b + ".");
+ }
+ return hits;
+}
+
+function fire_1(what, n) {
let hits = 0;
for (let i = 0; i < n_dice; ++i) {
let roll = roll_d6();
- if (roll == 6)
- ++hits;
+ if (roll == 6) ++hits;
log(what + " fires " + roll + ".");
}
return hits;
@@ -453,6 +480,13 @@ function count_swedish_frigates(where) {
return count_pieces(SE_FRIGATES, where);
}
+function count_available_american_frigates(where) {
+ let n = 0;
+ for (let space of FRIGATE_SPACES)
+ n += count_pieces(US_FRIGATES, space);
+ return n;
+}
+
function count_american_frigates(where) {
return count_pieces(US_FRIGATES, where);
}
@@ -477,33 +511,31 @@ function count_tripolitan_infantry(where) {
return count_pieces(TR_INFANTRY, where);
}
-function can_play_thomas_jefferson() {
- return game.us.core.includes(THOMAS_JEFFERSON);
-}
-
-function can_play_swedish_frigates_arrive() {
- return game.us.core.includes(SWEDISH_FRIGATES_ARRIVE);
-}
-
-function can_play_hamets_army_created() {
- return game.us.core.includes(HAMETS_ARMY_CREATED) &&
- count_american_frigates(ALEXANDRIA_HARBOR) > 0 &&
- game.year >= 1804;
+function is_naval_battle_location(space) {
+ let n_us = count_american_frigates(space);
+ let n_tr = count_tripolitan_corsairs(space) + count_allied_corsairs(space);
+ return (n_us > 0 && n_tr > 0);
}
-function can_play_yusuf_qaramanli() {
- let n = count_allied_corsairs(ALGIERS_HARBOR) +
- count_allied_corsairs(TRIPOLI_HARBOR) +
- count_allied_corsairs(TUNIS_HARBOR);
- return game.tr.core.includes(YUSUF_QARAMANLI) && n > 0;
+function is_naval_bombardment_location(space) {
+ let n_us = count_american_frigates(space);
+ let n_tr = count_tripolitan_infantry(space);
+ return (n_us > 0 && n_tr > 0);
}
-function can_play_murad_reis_breaks_out() {
- return game.tr.core.includes(MURAD_REIS_BREAKS_OUT);
+function is_naval_battle_or_bombardment_location(space) {
+ let n_us = count_american_frigates(space);
+ let n_tr_ships = count_tripolitan_corsairs(space) + count_allied_corsairs(space);
+ let n_tr_infantry = count_tripolitan_infantry(space);
+ return (n_us > 0 && (n_tr_ships > 0 || n_tr_infantry > 0));
}
-function can_play_constantinople_sends_aid() {
- return game.tr.core.includes(CONSTANTINOPLE_SENDS_AID) && game.derne_captured;
+function count_naval_battle_or_bombardment_locations() {
+ let n = 0;
+ for (let space of BATTLE_SPACES)
+ if (is_naval_battle_or_bombardment_location(space))
+ ++n;
+ return n;
}
function can_build_gunboat_in_malta() {
@@ -524,8 +556,8 @@ function start_of_year() {
game.season = SPRING;
- move_all_pieces(US_FRIGATES, TRACK_YEAR[game.year], GIBRALTAR_HARBOR);
- move_all_pieces(TR_FRIGATES, TRACK_YEAR[game.year], TRIPOLI_HARBOR);
+ move_all_pieces(US_FRIGATES, YEAR_TURN_TRACK[game.year], GIBRALTAR_HARBOR);
+ move_all_pieces(TR_FRIGATES, YEAR_TURN_TRACK[game.year], TRIPOLI_HARBOR);
if (game.year <= 1804) {
draw_cards(game.us.hand, game.us.deck, 6);
@@ -559,11 +591,6 @@ function end_tripolitan_play() {
end_of_season();
}
-const SPRING = 0;
-const SUMMER = 1;
-const FALL = 2;
-const WINTER = 3;
-
function end_of_season() {
if (game.season == WINTER) {
end_of_year();
@@ -585,26 +612,16 @@ function end_of_year() {
start_of_year();
}
-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', THOMAS_JEFFERSON);
- if (can_play_swedish_frigates_arrive())
- gen_action(view, 'card_event', SWEDISH_FRIGATES_ARRIVE);
- if (can_play_hamets_army_created())
- gen_action(view, 'card_event', HAMETS_ARMY_CREATED);
let build = can_build_gunboat_in_malta();
+ for (let c of game.us.core) {
+ if (can_play_american_event(c))
+ gen_action(view, 'card_event', c);
+ }
for (let c of game.us.hand) {
gen_action(view, 'card_move_frigates', c);
if (build)
@@ -624,6 +641,7 @@ states.american_play = {
discard_card(game.us, c, " to move up to two frigates");
goto_move_up_to_n_american_frigates(2);
},
+ card_event: play_american_event,
pass: function () {
log("");
log(game.active + " passes.");
@@ -636,14 +654,12 @@ states.tripolitan_play = {
if (is_inactive_player(current))
return view.prompt = "Tripolitan play.";
view.prompt = "Tripolitan play.";
- if (can_play_yusuf_qaramanli())
- gen_action(view, 'card_event', YUSUF_QARAMANLI);
- if (can_play_murad_reis_breaks_out())
- gen_action(view, 'card_event', MURAD_REIS_BREAKS_OUT);
- if (can_play_constantinople_sends_aid())
- gen_action(view, 'card_event', CONSTANTINOPLE_SENDS_AID);
let build = can_build_corsair_in_tripoli();
let raid = can_pirate_raid_from_tripoli();
+ for (let c of game.tr.core) {
+ if (can_play_tripolitan_event(c))
+ gen_action(view, 'card_event', c);
+ }
for (let c of game.tr.hand) {
if (build)
gen_action(view, 'card_build_corsair', c);
@@ -664,6 +680,7 @@ states.tripolitan_play = {
discard_card(game.tr, c, " to Pirate Raid with the corsairs from Tripoli");
goto_pirate_raid(TRIPOLI_HARBOR, TRIPOLI_PATROL_ZONE);
},
+ card_event: play_tripolitan_event,
pass: function () {
log("");
log(game.active + " passes.");
@@ -671,6 +688,8 @@ states.tripolitan_play = {
}
}
+// PIRATE RAID
+
function goto_pirate_raid(harbor, patrol_zone) {
game.where = patrol_zone;
interception_roll(harbor, patrol_zone);
@@ -686,7 +705,7 @@ function interception_roll(harbor, patrol_zone) {
let n_al = count_allied_corsairs(harbor);
let hits = 0;
hits += intercept("Swedish frigate", n_se);
- hits += intercept("US frigate", n_us);
+ hits += intercept("American frigate", n_us);
if (hits > n_tr + n_al)
hits = n_tr + n_al;
log(hits + " corsairs sink.");
@@ -698,19 +717,25 @@ function interception_roll(harbor, patrol_zone) {
move_one_piece(AL_CORSAIRS, harbor, TRIPOLITAN_SUPPLY);
}
+function give_gold(n) {
+ game.tr.gold += n;
+ if (game.tr.gold > 12)
+ game.tr.gold = 12;
+}
+
function capture_roll(harbor) {
let hits = 0;
hits += capture("Tripolitan corsair", count_tripolitan_corsairs(harbor));
hits += capture("Allied corsair", count_allied_corsairs(harbor));
log(hits + " merchant ships captured.");
-
- game.tr.gold += hits;
- if (game.tr.gold > 12)
- game.tr.gold = 12;
-
+ give_gold(hits);
// TODO: check victory
}
+// AMERICAN NAVAL MOVEMENT
+// TODO: click 'from' location to go back to selecting source?
+// TODO: select multiple frigates then destination?
+
function goto_move_up_to_n_american_frigates(n) {
game.moves = n;
game.active = US;
@@ -718,35 +743,6 @@ function goto_move_up_to_n_american_frigates(n) {
push_undo();
}
-function is_naval_battle_location(space) {
- let n_us = count_american_frigates(space);
- let n_tr = count_tripolitan_corsairs(space) + count_allied_corsairs(space);
- return (n_us > 0 && n_tr > 0);
-}
-
-function is_naval_bombardment_location(space) {
- let n_us = count_american_frigates(space);
- let n_tr = count_tripolitan_infantry(space);
- return (n_us > 0 && n_tr > 0);
-}
-
-function is_naval_battle_or_bombardment_location(space) {
- let n_us = count_american_frigates(space);
- let n_tr_ships = count_tripolitan_corsairs(space) + count_allied_corsairs(space);
- let n_tr_infantry = count_tripolitan_infantry(space);
- return (n_us > 0 && (n_tr_ships > 0 || n_tr_infantry > 0));
-}
-
-function count_naval_battle_or_bombardment_locations() {
- let n = 0;
- for (let space of BATTLE_SPACES)
- if (is_naval_battle_or_bombardment_location(space))
- ++n;
- return n;
-}
-
-// TODO: click 'from' location to go back to selecting source?
-
states.move_us_frigate_from = {
prompt: function (view, current) {
if (is_inactive_player(current))
@@ -855,6 +851,39 @@ states.select_combat = {
},
}
+// NAVAL BOMBARDMENT
+
+function goto_naval_bombardment() {
+ log("Naval bombardment in " + SPACES[game.where] + ".");
+ naval_bombardment_round();
+ end_naval_bombardment();
+}
+
+function naval_bombardment_round() {
+ let n_frigates = count_american_frigates(game.where);
+ let n_gunboats = count_american_gunboats(game.where);
+ let n_infantry = count_tripolitan_infantry(game.where);
+
+ let n_hits = 0;
+ n_hits += fire_2("American frigate", n_frigates);
+ n_hits += fire_1("American gunboat", n_gunboats);
+ if (n_hits > n_infantry)
+ n_hits = n_infantry;
+
+ log(n_hits + " Tripolitan infantry eliminated.");
+ for (let i = 0; i < n_hits; ++i)
+ move_one_piece(TR_INFANTRY, game.where, TRIPOLITAN_SUPPLY);
+}
+
+function end_naval_bombardment() {
+ move_all_pieces(US_FRIGATES, game.where, MALTA_HARBOR);
+ move_all_pieces(US_GUNBOATS, game.where, MALTA_HARBOR);
+ game.where = null;
+ goto_select_combat();
+}
+
+// NAVAL BATTLE
+
function goto_naval_battle() {
log("Naval battle in " + SPACES[game.where] + ".");
// TODO: battle cards
@@ -871,15 +900,15 @@ function naval_battle_round() {
let tr_hitpoints = n_tr_frigates * 2 + n_tr_corsairs + n_al_corsairs;
game.n_tr_hits = 0;
- game.n_tr_hits += fire("US frigate", 2 * n_us_frigates);
- game.n_tr_hits += fire("US gunboat", 1 * n_us_gunboats);
+ game.n_tr_hits += fire_2("American frigate", n_us_frigates);
+ game.n_tr_hits += fire_1("American gunboat", n_us_gunboats);
if (game.n_tr_hits > tr_hitpoints)
game.n_tr_hits = tr_hitpoints;
game.n_us_hits = 0;
- game.n_us_hits += fire("Tripolitan frigate", 2 * n_tr_frigates);
- game.n_us_hits += fire("Tripolitan corsair", 1 * n_tr_corsairs);
- game.n_us_hits += fire("Allied corsair", 1 * n_al_corsairs);
+ game.n_us_hits += fire_2("Tripolitan frigate", n_tr_frigates);
+ game.n_us_hits += fire_1("Tripolitan corsair", n_tr_corsairs);
+ game.n_us_hits += fire_1("Allied corsair", n_al_corsairs);
if (game.n_us_hits > us_hitpoints)
game.n_us_hits = us_hitpoints;
@@ -935,17 +964,17 @@ states.allocate_us_hits = {
--game.n_us_hits;
if (US_FRIGATES.includes(p)) {
if (game.damaged.includes(p)) {
- log("US frigate sinks!");
+ log("American frigate sinks!");
game.location[p] = TRIPOLITAN_SUPPLY;
remove_from_array(game.damaged, p);
// TODO: check victory
} else {
- log("US frigate is damaged.");
+ log("American frigate is damaged.");
game.damaged.push(p);
}
}
if (US_GUNBOATS.includes(p)) {
- log("US gunboat sinks.");
+ log("American gunboat sinks.");
move_one_piece(US_GUNBOATS, game.where, UNITED_STATES_SUPPLY);
}
},
@@ -1019,7 +1048,7 @@ function move_damaged_frigate_to_year_track(p, supply) {
if (game.year == 1806)
game.location[p] = supply;
else
- game.location[p] = TRACK_YEAR[game.year + 1];
+ game.location[p] = YEAR_TURN_TRACK[game.year + 1];
remove_from_array(game.damaged, p);
}
@@ -1047,35 +1076,334 @@ function end_naval_battle() {
goto_select_combat();
}
-function goto_naval_bombardment() {
- log("Naval bombardment in " + SPACES[game.where] + ".");
- naval_bombardment_round();
- end_naval_bombardment();
+// TRIPOLITAN EVENTS
+
+function can_play_tripolitan_event(card) {
+ switch (card) {
+ case YUSUF_QARAMANLI: return can_play_yusuf_qaramanli();
+ case MURAD_REIS_BREAKS_OUT: return can_play_murad_reis_breaks_out();
+ case CONSTANTINOPLE_SENDS_AID: return can_play_constantinople_sends_aid();
+ case US_SUPPLIES_RUN_LOW: return can_play_us_supplies_run_low();
+ case ALGERINE_CORSAIRS_RAID_1: return can_play_algerine_corsairs_raid();
+ case ALGERINE_CORSAIRS_RAID_2: return can_play_algerine_corsairs_raid();
+ case MOROCCAN_CORSAIRS_RAID_1: return can_play_moroccan_corsairs_raid();
+ case MOROCCAN_CORSAIRS_RAID_2: return can_play_moroccan_corsairs_raid();
+ case TUNISIAN_CORSAIRS_RAID_1: return can_play_tunisian_corsairs_raid();
+ case TUNISIAN_CORSAIRS_RAID_2: return can_play_tunisian_corsairs_raid();
+ case TROOPS_TO_DERNE: return can_play_troops_to_derne();
+ case TROOPS_TO_BENGHAZI: return can_play_troops_to_benghazi();
+ case TROOPS_TO_TRIPOLI: return can_play_troops_to_tripoli();
+ case STORMS: return can_play_storms();
+ case TRIPOLI_ATTACKS: return can_play_tripoli_attacks();
+ case SWEDEN_PAYS_TRIBUTE: return can_play_sweden_pays_tribute();
+ case TRIPOLI_ACQUIRES_CORSAIRS: return can_play_tripoli_acquires_corsairs();
+ case THE_PHILADELPHIA_RUNS_AGROUND: return can_play_the_philadelphia_runs_aground();
+ case ALGIERS_DECLARES_WAR: return true;
+ case MOROCCO_DECLARES_WAR: return true;
+ case TUNIS_DECLARES_WAR: return true;
+ }
+ return false;
}
-function naval_bombardment_round() {
- let n_frigates = count_american_frigates(game.where);
- let n_gunboats = count_american_gunboats(game.where);
- let n_infantry = count_tripolitan_infantry(game.where);
+function can_play_yusuf_qaramanli() {
+ let n = count_allied_corsairs(ALGIERS_HARBOR) +
+ count_allied_corsairs(TRIPOLI_HARBOR) +
+ count_allied_corsairs(TUNIS_HARBOR);
+ return n > 0;
+}
- let n_hits = 0;
- n_hits += fire("US frigate", 2 * n_frigates);
- n_hits += fire("US gunboat", 1 * n_gunboats);
- if (n_hits > n_infantry)
- n_hits = n_infantry;
+function can_play_murad_reis_breaks_out() {
+ return true;
+}
- log(n_hits + " Tripolitan infantry eliminated.");
- for (let i = 0; i < n_hits; ++i)
- move_one_piece(TR_INFANTRY, game.where, TRIPOLITAN_SUPPLY);
+function can_play_constantinople_sends_aid() {
+ // TODO: check where hamet's army is located instead of explicit flag
+ return game.derne_captured;
}
-function end_naval_bombardment() {
- move_all_pieces(US_FRIGATES, game.where, MALTA_HARBOR);
- move_all_pieces(US_GUNBOATS, game.where, MALTA_HARBOR);
- game.where = null;
- goto_select_combat();
+function play_tripolitan_event(card) {
+ play_card(game.tr, card);
+ switch (card) {
+ case YUSUF_QARAMANLI: return play_yusuf_qaramanli();
+ case MURAD_REIS_BREAKS_OUT: return play_murad_reis_breaks_out();
+ case CONSTANTINOPLE_SENDS_AID: return play_constantinople_sends_aid();
+ case US_SUPPLIES_RUN_LOW: return play_us_supplies_run_low();
+ case ALGERINE_CORSAIRS_RAID_1: return play_algerine_corsairs_raid();
+ case ALGERINE_CORSAIRS_RAID_2: return play_algerine_corsairs_raid();
+ case MOROCCAN_CORSAIRS_RAID_1: return play_moroccan_corsairs_raid();
+ case MOROCCAN_CORSAIRS_RAID_2: return play_moroccan_corsairs_raid();
+ case TUNISIAN_CORSAIRS_RAID_1: return play_tunisian_corsairs_raid();
+ case TUNISIAN_CORSAIRS_RAID_2: return play_tunisian_corsairs_raid();
+ case TROOPS_TO_DERNE: return play_troops_to_derne();
+ case TROOPS_TO_BENGHAZI: return play_troops_to_benghazi();
+ case TROOPS_TO_TRIPOLI: return play_troops_to_tripoli();
+ case STORMS: return play_storms();
+ case TRIPOLI_ATTACKS: return play_tripoli_attacks();
+ case SWEDEN_PAYS_TRIBUTE: return play_sweden_pays_tribute();
+ case TRIPOLI_ACQUIRES_CORSAIRS: return play_tripoli_acquires_corsairs();
+ case THE_PHILADELPHIA_RUNS_AGROUND: return play_the_philadelphia_runs_aground();
+ case ALGIERS_DECLARES_WAR: return play_algiers_declares_war();
+ case MOROCCO_DECLARES_WAR: return play_morocco_declares_war();
+ case TUNIS_DECLARES_WAR: return play_tunis_declares_war();
+ }
+ throw Error(card + " is not a Tripolitan event card.");
+}
+
+// UNITED STATES EVENTS
+
+function can_play_american_event(card) {
+ switch (card) {
+ case THOMAS_JEFFERSON: return can_play_thomas_jefferson();
+ case SWEDISH_FRIGATES_ARRIVE: return can_play_swedish_frigates_arrive();
+ case HAMETS_ARMY_CREATED: return can_play_hamets_army_created();
+ // case TREATY_OF_PEACE_AND_AMITY: return can_play_treaty_of_peace_and_amity();
+ // case ASSAULT_ON_TRIPOLI: return can_play_assault_on_tripoli();
+ case NAVAL_MOVEMENT_1: return true;
+ case NAVAL_MOVEMENT_2: return true;
+ case NAVAL_MOVEMENT_3: return true;
+ case NAVAL_MOVEMENT_4: return true;
+ case EARLY_DEPLOYMENT: return can_play_early_deployment();
+ case A_SHOW_OF_FORCE: return can_play_a_show_of_force();
+ case TRIBUTE_PAID: return can_play_tribute_paid();
+ // case CONSTANTINOPLE_DEMANDS_TRIBUTE: return can_play_constantinople_demands_tribute();
+ // case HAMET_RECRUITS_BEDOUINS: return can_play_hamet_recruits_bedouins();
+ // case BAINBRIDGE_SUPPLIES_INTEL: return can_play_bainbridge_supplies_intel();
+ // case CONGRESS_AUTHORIZES_ACTION: return can_play_congress_authorizes_action();
+ // case CORSAIRS_CONFISCATED: return can_play_corsairs_confiscated();
+ // case BURN_THE_PHILADELPHIA: return can_play_burn_the_philadelphia();
+ // case LAUNCH_THE_INTREPID: return can_play_launch_the_intrepid();
+ // case GENERAL_EATON_ATTACKS_DERNE: return can_play_general_eaton_attacks_derne();
+ // case GENERAL_EATON_ATTACKS_BENGHAZI: return can_play_general_eaton_attacks_benghazi();
+ }
+ return false;
+}
+
+function play_american_event(card) {
+ play_card(game.us, card);
+ switch (card) {
+ case THOMAS_JEFFERSON: return play_thomas_jefferson();
+ case SWEDISH_FRIGATES_ARRIVE: return play_swedish_frigates_arrive();
+ case HAMETS_ARMY_CREATED: return play_hamets_army_created();
+ case TREATY_OF_PEACE_AND_AMITY: return play_treaty_of_peace_and_amity();
+ case ASSAULT_ON_TRIPOLI: return play_assault_on_tripoli();
+ case NAVAL_MOVEMENT_1: return play_naval_movement();
+ case NAVAL_MOVEMENT_2: return play_naval_movement();
+ case NAVAL_MOVEMENT_3: return play_naval_movement();
+ case NAVAL_MOVEMENT_4: return play_naval_movement();
+ case EARLY_DEPLOYMENT: return play_early_deployment();
+ case A_SHOW_OF_FORCE: return play_a_show_of_force();
+ case TRIBUTE_PAID: return play_tribute_paid();
+ case CONSTANTINOPLE_DEMANDS_TRIBUTE: return play_constantinople_demands_tribute();
+ case HAMET_RECRUITS_BEDOUINS: return play_hamet_recruits_bedouins();
+ case BAINBRIDGE_SUPPLIES_INTEL: return play_bainbridge_supplies_intel();
+ case CONGRESS_AUTHORIZES_ACTION: return play_congress_authorizes_action();
+ case CORSAIRS_CONFISCATED: return play_corsairs_confiscated();
+ case BURN_THE_PHILADELPHIA: return play_burn_the_philadelphia();
+ case LAUNCH_THE_INTREPID: return play_launch_the_intrepid();
+ case GENERAL_EATON_ATTACKS_DERNE: return play_general_eaton_attacks_derne();
+ case GENERAL_EATON_ATTACKS_BENGHAZI: return play_general_eaton_attacks_benghazi();
+ }
+ throw Error(card + " is not an American event card.");
+}
+
+function can_play_thomas_jefferson() {
+ return true;
+}
+
+function play_thomas_jefferson() {
+ goto_move_up_to_n_american_frigates(8);
+}
+
+function can_play_swedish_frigates_arrive() {
+ return true;
+}
+
+function play_swedish_frigates_arrive() {
+ move_all_pieces(SE_FRIGATES, UNITED_STATES_SUPPLY, TRIPOLI_PATROL_ZONE);
+ end_american_play();
+}
+
+function can_play_hamets_army_created() {
+ return (count_american_frigates(ALEXANDRIA_HARBOR) > 0) && (game.year >= 1804);
+}
+
+function play_hamets_army_created() {
+ move_one_piece(US_MARINES, UNITED_STATES_SUPPLY, ALEXANDRIA_HARBOR);
+ move_one_piece(AR_INFANTRY, UNITED_STATES_SUPPLY, ALEXANDRIA_HARBOR);
+ move_one_piece(AR_INFANTRY, UNITED_STATES_SUPPLY, ALEXANDRIA_HARBOR);
+ move_one_piece(AR_INFANTRY, UNITED_STATES_SUPPLY, ALEXANDRIA_HARBOR);
+ move_one_piece(AR_INFANTRY, UNITED_STATES_SUPPLY, ALEXANDRIA_HARBOR);
+ move_one_piece(AR_INFANTRY, UNITED_STATES_SUPPLY, ALEXANDRIA_HARBOR);
+ game.hamets_army_created = 1;
+ end_american_play();
+}
+
+function can_play_naval_movement() {
+ return true;
+}
+
+function play_naval_movement() {
+ goto_move_up_to_n_american_frigates(4);
+}
+
+function can_play_early_deployment() {
+ if (game.year < 1806)
+ return count_american_frigates(YEAR_TURN_TRACK[game.year+1]) > 0;
+ return false;
+}
+
+function play_early_deployment() {
+ game.state = 'early_deployment';
+}
+
+states.early_deployment = {
+ prompt: function (view, current) {
+ view.prompt = "United States: Early Deployment.";
+ if (is_inactive_player(current))
+ return;
+ for (let space of PATROL_ZONES)
+ gen_action(view, 'space', space);
+ },
+ space: function (space) {
+ log(game.active + " places frigate in " + SPACES[space] + ".");
+ move_one_piece(US_FRIGATES, YEAR_TURN_TRACK[game.year+1], space);
+ end_american_play();
+ },
+}
+
+function can_play_a_show_of_force() {
+ if (count_available_american_frigates() < 3)
+ return false;
+ if (count_allied_corsairs(ALGIERS_HARBOR) > 0) return true;
+ if (count_allied_corsairs(TANGIER_HARBOR) > 0) return true;
+ if (count_allied_corsairs(TUNIS_HARBOR) > 0) return true;
+ return false;
+}
+
+function play_a_show_of_force() {
+ game.state = 'a_show_of_force_where';
+}
+
+states.a_show_of_force_where = {
+ prompt: function (view, current) {
+ view.prompt = "United States: A Show of Force.";
+ if (is_inactive_player(current))
+ return;
+ view.prompt += " Select an active ally of Tripoli.";
+ if (count_allied_corsairs(ALGIERS_HARBOR) > 0)
+ gen_action(view, 'space', ALGIERS_HARBOR);
+ if (count_allied_corsairs(TANGIER_HARBOR) > 0)
+ gen_action(view, 'space', TANGIER_HARBOR);
+ if (count_allied_corsairs(TUNIS_HARBOR) > 0)
+ gen_action(view, 'space', TUNIS_HARBOR);
+ },
+ space: function (space) {
+ push_undo();
+ game.where = space;
+ game.state = 'a_show_of_force_who';
+ },
+}
+
+states.a_show_of_force_who = {
+ prompt: function (view, current) {
+ view.prompt = "United States: A Show of Force.";
+ if (is_inactive_player(current))
+ return;
+ view.prompt += " Move 3 frigates to " + SPACES[game.where] + ".";
+ gen_action_undo(view);
+ if (count_american_frigates(game.where) == 3) {
+ gen_action(view, 'next');
+ } else {
+ for (let space of FRIGATE_SPACES)
+ if (space != game.where)
+ if (count_american_frigates(space) > 0)
+ gen_action(view, 'space', space);
+ }
+ },
+ space: function (space) {
+ push_undo();
+ log(game.active + " moves a frigate from " + SPACES[space] + " to " + SPACES[game.where] + ".");
+ move_one_piece(US_FRIGATES, space, game.where);
+ },
+ next: function () {
+ clear_undo();
+ log("All allied corsairs from " + SPACES[game.where] + " return to the supply.");
+ move_all_pieces(AL_CORSAIRS, game.where, TRIPOLITAN_SUPPLY);
+ game.where = null;
+ end_american_play();
+ },
+ undo: pop_undo
+}
+
+function can_play_tribute_paid() {
+ if (count_available_american_frigates() < 1)
+ return false;
+ if (count_allied_corsairs(ALGIERS_HARBOR) > 0) return true;
+ if (count_allied_corsairs(TANGIER_HARBOR) > 0) return true;
+ if (count_allied_corsairs(TUNIS_HARBOR) > 0) return true;
+ return false;
}
+function play_tribute_paid() {
+ game.state = 'tribute_paid_where';
+}
+
+states.tribute_paid_where = {
+ prompt: function (view, current) {
+ view.prompt = "United States: Tribute Paid.";
+ if (is_inactive_player(current))
+ return;
+ view.prompt += " Select an active ally of Tripoli.";
+ if (count_allied_corsairs(ALGIERS_HARBOR) > 0)
+ gen_action(view, 'space', ALGIERS_HARBOR);
+ if (count_allied_corsairs(TANGIER_HARBOR) > 0)
+ gen_action(view, 'space', TANGIER_HARBOR);
+ if (count_allied_corsairs(TUNIS_HARBOR) > 0)
+ gen_action(view, 'space', TUNIS_HARBOR);
+ },
+ space: function (space) {
+ push_undo();
+ game.where = space;
+ game.state = 'tribute_paid_who';
+ },
+}
+
+states.tribute_paid_who = {
+ prompt: function (view, current) {
+ view.prompt = "United States: Tribute Paid.";
+ if (is_inactive_player(current))
+ return;
+ view.prompt += " Move a frigate to " + SPACES[game.where] + ".";
+ gen_action_undo(view);
+ if (count_american_frigates(game.where) == 1) {
+ gen_action(view, 'next');
+ } else {
+ for (let space of FRIGATE_SPACES)
+ if (space != game.where)
+ if (count_american_frigates(space) > 0)
+ gen_action(view, 'space', space);
+ }
+ },
+ space: function (space) {
+ push_undo();
+ log(game.active + " moves a frigate from " + SPACES[space] + " to " + SPACES[game.where] + ".");
+ move_one_piece(US_FRIGATES, space, game.where);
+ },
+ next: function () {
+ clear_undo();
+ log("All allied corsairs from " + SPACES[game.where] + " return to the supply.");
+ move_all_pieces(AL_CORSAIRS, game.where, TRIPOLITAN_SUPPLY);
+ log("Tripolitania receives two gold coins.");
+ give_gold(2);
+ // TODO: check victory
+ game.where = null;
+ end_american_play();
+ },
+ undo: pop_undo
+}
+
+// SETUP
+
states.game_over = {
prompt: function (view, current) {
return view.prompt = game.victory;
@@ -1105,6 +1433,7 @@ exports.setup = function (scenario, players) {
discard: [],
gold: 0,
},
+ hamets_army_created: 0,
derne_captured: 0,
where: null,
undo: [],