summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2021-06-06 17:29:40 +0200
committerTor Andersson <tor@ccxvii.net>2023-02-18 12:12:42 +0100
commit7edd71f76123e10a15daa5918f7f3eae2dfbf062 (patch)
treecd8fb0b211da8ee0bb3b6bc27b4b2914422cb11d
parent4befc7eb54e2f31709f0e29936570605abde8bbc (diff)
downloadshores-of-tripoli-7edd71f76123e10a15daa5918f7f3eae2dfbf062.tar.gz
tripoli: Start moving frigates.
-rw-r--r--rules.js222
-rw-r--r--ui.js99
2 files changed, 253 insertions, 68 deletions
diff --git a/rules.js b/rules.js
index d43f1b2..62f8693 100644
--- a/rules.js
+++ b/rules.js
@@ -57,6 +57,32 @@ const TRACK_1804 = get_space_id("1804");
const TRACK_1805 = get_space_id("1805");
const TRACK_1806 = get_space_id("1806");
+const TRACK_YEAR = {
+ 1801: TRACK_1801,
+ 1802: TRACK_1802,
+ 1803: TRACK_1803,
+ 1804: TRACK_1804,
+ 1805: TRACK_1805,
+ 1806: TRACK_1806,
+};
+
+const FRIGATE_SPACES = [
+ ALEXANDRIA_HARBOR,
+ ALGIERS_HARBOR,
+ ALGIERS_PATROL_ZONE,
+ BENGHAZI_HARBOR,
+ DERNE_HARBOR,
+ GIBRALTAR_HARBOR,
+ GIBRALTAR_PATROL_ZONE,
+ MALTA_HARBOR,
+ TANGIER_HARBOR,
+ TANGIER_PATROL_ZONE,
+ TRIPOLI_HARBOR,
+ TRIPOLI_PATROL_ZONE,
+ TUNIS_HARBOR,
+ TUNIS_PATROL_ZONE,
+];
+
const THOMAS_JEFFERSON = 1;
const SWEDISH_FRIGATES_ARRIVE = 2;
const HAMETS_ARMY_CREATED = 3;
@@ -176,6 +202,43 @@ 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 states = {};
let game = null;
@@ -263,14 +326,17 @@ function reset_deck() {
return deck;
}
-function deal_cards(deck, n) {
- let hand = [];
+function reshuffle_discard(deck, discard) {
+ while (discard.length > 0)
+ deck.push(discard.pop());
+}
+
+function draw_cards(hand, deck, n) {
for (let i = 0; i < n; ++i) {
let c = Math.floor(Math.random() * deck.length);
hand.push(deck[c]);
deck.splice(c, 1);
}
- return hand;
}
function count_pieces(list, where) {
@@ -292,7 +358,8 @@ function play_card(player, card) {
log("");
log(game.active + " plays \"" + CARD_NAMES[card] + "\".");
remove_from_array(player.hand, card);
- player.discard.push(card);
+ if (!should_remove_after_play(card))
+ player.discard.push(card);
}
function deploy(piece_name, space) {
@@ -330,15 +397,15 @@ function count_allied_corsairs(where) {
}
function can_play_thomas_jefferson() {
- return game.us.core.includes(1);
+ return game.us.core.includes(THOMAS_JEFFERSON);
}
function can_play_swedish_frigates_arrive() {
- return game.us.core.includes(2);
+ return game.us.core.includes(SWEDISH_FRIGATES_ARRIVE);
}
function can_play_hamets_army_created() {
- return game.us.core.includes(3) &&
+ return game.us.core.includes(HAMETS_ARMY_CREATED) &&
count_american_frigates(ALEXANDRIA_HARBOR) > 0 &&
game.year >= 1804;
}
@@ -347,27 +414,21 @@ 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(1) && n > 0;
+ return game.tr.core.includes(YUSUF_QARAMANLI) && n > 0;
}
function can_play_murad_reis_breaks_out() {
- return game.tr.core.includes(2);
+ return game.tr.core.includes(MURAD_REIS_BREAKS_OUT);
}
function can_play_constantinople_sends_aid() {
- return game.tr.core.includes(3) && game.derne_captured;
+ return game.tr.core.includes(CONSTANTINOPLE_SENDS_AID) && 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;
}
@@ -376,7 +437,30 @@ function can_pirate_raid_from_tripoli() {
return count_pieces(TR_CORSAIRS, TRIPOLI_HARBOR) > 0;
}
-function start_year() {
+function start_of_year() {
+ log("");
+ log("Start of " + game.year + ".");
+
+ move_all_pieces(US_FRIGATES, TRACK_YEAR[game.year], GIBRALTAR_HARBOR);
+ move_all_pieces(TR_FRIGATES, TRACK_YEAR[game.year], TRIPOLI_HARBOR);
+
+ if (game.year <= 1804) {
+ draw_cards(game.us.hand, game.us.deck, 6);
+ draw_cards(game.tr.hand, game.tr.deck, 6);
+ }
+ if (game.year == 1805) {
+ reshuffle_discard(game.us.deck, game.us.discard);
+ draw_cards(game.us.hand, game.us.deck, 6);
+ reshuffle_discard(game.tr.deck, game.tr.discard);
+ draw_cards(game.tr.hand, game.tr.deck, 6);
+ }
+ if (game.year == 1806) {
+ draw_cards(game.us.hand, game.us.deck, game.us.deck.length);
+ draw_cards(game.tr.hand, game.tr.deck, game.tr.deck.length);
+ }
+
+ // TODO: hand limit
+
game.active = US;
game.state = 'american_play';
}
@@ -387,8 +471,33 @@ function end_american_play() {
}
function end_tripolitan_play() {
- game.active = US;
- game.state = 'american_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();
+ } else {
+ ++game.season;
+ game.active = US;
+ game.state = 'american_play';
+ }
+}
+
+function end_of_year() {
+ if (game.year == 1806) {
+ game.result = 'Draw';
+ game.victory = "The game ends in a draw.";
+ game.state = 'game_over';
+ return;
+ }
+ ++game.year;
+ start_of_year();
}
function can_play_american_event(c) {
@@ -410,11 +519,11 @@ states.american_play = {
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.hand) {
- if (can_build_gunboat_in_malta())
+ gen_action(view, 'card_move_frigates', c);
+ if (build)
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);
}
@@ -428,7 +537,7 @@ states.american_play = {
},
card_move_frigates: function (c) {
discard_card(game.us, c, " to move up to two frigates");
- end_american_play();
+ goto_move_up_to_n_american_frigates(2);
},
pass: function () {
log("");
@@ -448,10 +557,13 @@ states.tripolitan_play = {
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();
+ console.log("tripolitan_play", build, raid);
for (let c of game.tr.hand) {
- if (can_build_corsair_in_tripoli())
+ if (build)
gen_action(view, 'card_build_corsair', c);
- if (can_pirate_raid_from_tripoli())
+ if (raid)
gen_action(view, 'card_pirate_raid', c);
if (can_play_tripolitan_event(c))
gen_action(view, 'card_event', c);
@@ -475,6 +587,60 @@ states.tripolitan_play = {
}
}
+function goto_move_up_to_n_american_frigates(n) {
+ game.moves = n;
+ game.active = US;
+ game.state = 'move_us_frigate_from';
+ push_undo();
+}
+
+states.move_us_frigate_from = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "United States: Move up to " + game.moves + " frigates.";
+ view.prompt = "United States: Move up to " + game.moves + " frigates."
+ if (game.moves > 0) {
+ view.prompt += " Select a frigate to move.";
+ for (let s of FRIGATE_SPACES) {
+ if (count_american_frigates(s) > 0)
+ gen_action(view, 'space', s);
+ }
+ }
+ gen_action(view, 'next');
+ gen_action_undo(view);
+ },
+ space: function (space) {
+ push_undo();
+ game.from = space;
+ game.state = 'move_us_frigate_to'
+ },
+ next: function () {
+ // resolve naval battles
+ // resolve bombardment
+ end_american_play();
+ },
+ undo: pop_undo
+}
+
+states.move_us_frigate_to = {
+ prompt: function (view, current) {
+ if (is_inactive_player(current))
+ return view.prompt = "United States: Move up to " + game.moves + " frigates.";
+ view.prompt = "United States: Move up to " + game.moves + " frigates. Select a destation.";
+ for (let s of FRIGATE_SPACES)
+ if (s != game.from)
+ gen_action(view, 'space', s);
+ gen_action_undo(view);
+ },
+ space: function (space) {
+ move_one_piece(US_FRIGATES, game.from, space);
+ --game.moves;
+ game.from = null;
+ game.state = 'move_us_frigate_from'
+ },
+ undo: pop_undo
+}
+
states.game_over = {
prompt: function (view, current) {
return view.prompt = game.victory;
@@ -504,6 +670,7 @@ exports.setup = function (scenario, players) {
coins: 0,
},
derne_captured: 0,
+ undo: [],
};
game.tr.core.push(YUSUF_QARAMANLI);
@@ -519,9 +686,6 @@ exports.setup = function (scenario, players) {
game.tr.deck.push(i+27);
}
- game.us.hand = deal_cards(game.us.deck, 6);
- game.tr.hand = deal_cards(game.tr.deck, 6);
-
deploy("us_frigate_1", GIBRALTAR_HARBOR);
deploy("us_frigate_2", GIBRALTAR_HARBOR);
deploy("us_frigate_3", GIBRALTAR_HARBOR);
@@ -573,7 +737,7 @@ exports.setup = function (scenario, players) {
for (let i = 9; i <= 20; ++i)
deploy("tr_infantry_" + i, TRIPOLITAN_SUPPLY);
- start_year();
+ start_of_year();
return game;
}
diff --git a/ui.js b/ui.js
index cd711d8..b9b8928 100644
--- a/ui.js
+++ b/ui.js
@@ -59,37 +59,43 @@ function on_blur(evt) {
function on_pass() { if (game.actions) { send_action('pass', null); } }
function on_undo() { if (game.actions) { send_action('undo', null); } }
+function on_next() { if (game.actions) { send_action('next', null); } }
+
+function on_click_space(evt) { send_action('space', evt.target.space); }
+function on_click_piece(evt) { send_action('piece', evt.target.piece); }
function build_map() {
- let i = 0;
- for (let space of SPACES) {
+ for (let i = 0; i < SPACES.length; ++i) {
+ let space = SPACES[i];
let id = space.replace(/ /g, "_").toLowerCase();
let e = map.getElementById(id);
if (e) {
e.addEventListener("mouseenter", on_focus_space);
e.addEventListener("mouseleave", on_blur);
- e.space = space;
- ui.spaces[i++] = e;
+ e.addEventListener("click", on_click_space);
+ e.space = i;
+ ui.spaces[i] = e;
}
}
- i = 0;
- for (let piece of PIECES) {
+ for (let i = 0; i < PIECES.length; ++i) {
+ let piece = PIECES[i];
let e = map.getElementById(piece);
if (e) {
e.addEventListener("mouseenter", on_focus_piece);
e.addEventListener("mouseleave", on_blur);
- e.piece = piece;
- ui.pieces[i++] = e;
+ e.addEventListener("click", on_click_piece);
+ e.piece = i;
+ ui.pieces[i] = e;
}
}
- for (i = 1; i <= 27; ++i) {
+ for (let i = 1; i <= 27; ++i) {
let e = ui.cards[i] = document.getElementById("us_card_"+i);
- e.addEventListener("click", on_card);
+ e.addEventListener("click", on_click_card);
e.card = i;
}
- for (i = 28; i <= 54; ++i) {
+ for (let i = 28; i <= 54; ++i) {
let e = ui.cards[i] = document.getElementById("tr_card_"+(i-27));
- e.addEventListener("click", on_card);
+ e.addEventListener("click", on_click_card);
e.card = i;
}
}
@@ -118,10 +124,14 @@ function update_cards() {
function on_update() {
show_action_button("#button_pass", "pass");
+ show_action_button("#button_next", "next");
+ show_action_button("#button_undo", "undo");
update_year_marker(game.year);
update_season_marker(game.season);
update_pieces(game.location);
+ update_pieces();
update_cards();
+ update_spaces();
}
function update_year_marker(year) {
@@ -163,32 +173,43 @@ function layout_space(location, s, x0, y0, wrap, dx=45, dy=30) {
}
}
-function update_pieces(location) {
- layout_space(location, UNITED_STATES_SUPPLY, 1933, 180, 6, 38, 26);
- layout_space(location, TRIPOLITAN_SUPPLY, 2195, 180, 6, 38, 26);
-
- layout_space(location, TRACK_1801, YEAR_X[1801], 625, 1);
- layout_space(location, TRACK_1802, YEAR_X[1802], 625, 1);
- layout_space(location, TRACK_1803, YEAR_X[1803], 625, 1);
- layout_space(location, TRACK_1804, YEAR_X[1804], 625, 1);
- layout_space(location, TRACK_1805, YEAR_X[1805], 625, 1);
- layout_space(location, TRACK_1806, YEAR_X[1806], 625, 1);
-
- layout_space(location, ALEXANDRIA_HARBOR, 2335, 454, 3);
- layout_space(location, ALGIERS_HARBOR, 883, 318, 3);
- layout_space(location, BENGHAZI_HARBOR, 1877, 583, 3);
- layout_space(location, DERNE_HARBOR, 2030, 437, 3);
- layout_space(location, GIBRALTAR_HARBOR, 374, 216, 3);
- layout_space(location, MALTA_HARBOR, 1592, 189, 3);
- layout_space(location, TANGIER_HARBOR, 296, 426, 3);
- layout_space(location, TRIPOLI_HARBOR, 1416, 604, 4);
- layout_space(location, TUNIS_HARBOR, 1232, 278, 3);
-
- layout_space(location, ALGIERS_PATROL_ZONE, 875, 170, 3);
- layout_space(location, GIBRALTAR_PATROL_ZONE, 560, 245, 3);
- layout_space(location, TANGIER_PATROL_ZONE, 125, 410, 3);
- layout_space(location, TRIPOLI_PATROL_ZONE, 1575, 390, 6);
- layout_space(location, TUNIS_PATROL_ZONE, 1300, 130, 3);
+function update_pieces() {
+ layout_space(game.location, UNITED_STATES_SUPPLY, 1933, 180, 6, 38, 26);
+ layout_space(game.location, TRIPOLITAN_SUPPLY, 2195, 180, 6, 38, 26);
+
+ layout_space(game.location, TRACK_1801, YEAR_X[1801], 625, 1);
+ layout_space(game.location, TRACK_1802, YEAR_X[1802], 625, 1);
+ layout_space(game.location, TRACK_1803, YEAR_X[1803], 625, 1);
+ layout_space(game.location, TRACK_1804, YEAR_X[1804], 625, 1);
+ layout_space(game.location, TRACK_1805, YEAR_X[1805], 625, 1);
+ layout_space(game.location, TRACK_1806, YEAR_X[1806], 625, 1);
+
+ layout_space(game.location, ALEXANDRIA_HARBOR, 2335, 454, 3);
+ layout_space(game.location, ALGIERS_HARBOR, 883, 318, 3);
+ layout_space(game.location, BENGHAZI_HARBOR, 1877, 583, 3);
+ layout_space(game.location, DERNE_HARBOR, 2030, 437, 3);
+ layout_space(game.location, GIBRALTAR_HARBOR, 374, 216, 3);
+ layout_space(game.location, MALTA_HARBOR, 1592, 189, 3);
+ layout_space(game.location, TANGIER_HARBOR, 296, 426, 3);
+ layout_space(game.location, TRIPOLI_HARBOR, 1416, 604, 4);
+ layout_space(game.location, TUNIS_HARBOR, 1232, 278, 3);
+
+ layout_space(game.location, ALGIERS_PATROL_ZONE, 875, 170, 3);
+ layout_space(game.location, GIBRALTAR_PATROL_ZONE, 560, 245, 3);
+ layout_space(game.location, TANGIER_PATROL_ZONE, 125, 410, 3);
+ layout_space(game.location, TRIPOLI_PATROL_ZONE, 1575, 390, 6);
+ layout_space(game.location, TUNIS_PATROL_ZONE, 1300, 130, 3);
+}
+
+function update_spaces() {
+ for (let space in ui.spaces)
+ ui.spaces[space].classList.remove('enabled');
+ if (game.actions && game.actions.space) {
+ for (let space of game.actions.space) {
+ console.log("enable space " + space);
+ ui.spaces[space].classList.add('enabled');
+ }
+ }
}
/* CARD ACTION MENU */
@@ -246,7 +267,7 @@ function is_card_action(action, card) {
return game.actions && game.actions[action] && game.actions[action].includes(card);
}
-function on_card(evt) {
+function on_click_card(evt) {
if (game.actions) {
let card = evt.target.card;
if (is_card_action('discard', card)) {