summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTor Andersson <tor@ccxvii.net>2024-11-03 01:57:36 +0100
committerTor Andersson <tor@ccxvii.net>2024-11-06 01:49:09 +0100
commit719b7f1cd0917980021f8715c7f5bf8a642254f6 (patch)
treefb7005a1273955a71f52d135bb70330715b44dcd
parent3c1ae85c4614cabbc84d2aa515885028c3e5bb0b (diff)
downloadmaria-719b7f1cd0917980021f8715c7f5bf8a642254f6.tar.gz
Propose deals and list accepted deals in political display.
-rw-r--r--play.css35
-rw-r--r--play.html60
-rw-r--r--play.js113
-rw-r--r--rules.js339
4 files changed, 473 insertions, 74 deletions
diff --git a/play.css b/play.css
index 57459ea..5ad6c16 100644
--- a/play.css
+++ b/play.css
@@ -190,6 +190,41 @@ header.your_turn.austria { background-color: var(--color-light-austria); }
--color-reserve: #59594c;
}
+/* DEALS */
+
+dialog {
+ background-color: #f3ebd4;
+}
+
+dialog button {
+ margin-left: 8px;
+}
+
+#political_body table {
+ width: 100%;
+ background-color: var(--color-light-political);
+ border: 1px solid #0008;
+}
+
+#political_body div.deal {
+ margin: 16px 8px 8px 8px;
+}
+
+#political_body td {
+ border: 1px solid #0004;
+ padding: 4px;
+}
+
+#political_body td img {
+ display: block;
+ border: 1px solid black;
+}
+
+#political_body th {
+ font-weight: normal;
+ background-color: #0002;
+}
+
/* PANELS */
.panel {
diff --git a/play.html b/play.html
index c5203ec..bd8cb5b 100644
--- a/play.html
+++ b/play.html
@@ -38,8 +38,10 @@
<img src="images/shaking-hands.svg">
</summary>
<menu>
- <li id="propose_subsidy_menu" onclick="send_action('propose_subsidy')">Propose subsidy contract
- <li id="cancel_subsidy_menu" onclick="send_action('cancel_subsidy')">Cancel subsidy contract
+ <li id="propose_subsidy_menu" onclick="propose_subsidy()">Propose subsidy contract
+ <li id="cancel_subsidy_menu" onclick="cancel_subsidy()">Cancel subsidy contract
+ <li class="separator">
+ <li id="propose_deal_menu" onclick="propose_deal()">Propose deal
</menu>
</details>
</div>
@@ -122,6 +124,8 @@
<div id="pc_show" style="display:flex;flex-wrap:wrap;gap:18px;">
</div>
</div>
+ <div class="deal" id="active_deal_list"></div>
+ <div class="deal" id="proposed_deal_list"></div>
</div>
</div>
@@ -141,4 +145,56 @@
<footer id="status"></footer>
+<dialog id="propose_deal_dlog">
+ <form id="propose_deal_form">
+ <select name="a_power">
+ <option value="0">France</option>
+ <option value="1">Prussia</option>
+ <option value="2">Pragmatic Army</option>
+ <option value="3">Austria</option>
+ <option value="4">Bavaria</option>
+ <option value="5">Saxony</option>
+ </select>
+ <br>
+ <textarea name="a_promise" placeholder="Promise..." rows=3 cols=40></textarea>
+ <br><br>
+
+ <select name="b_power">
+ <option value="0">France</option>
+ <option value="1">Prussia</option>
+ <option value="2">Pragmatic Army</option>
+ <option value="3">Austria</option>
+ <option value="4">Bavaria</option>
+ <option value="5">Saxony</option>
+ </select>
+ <br>
+ <textarea name="b_promise" placeholder="Promise..." rows=3 cols=40></textarea>
+ <br><br>
+
+ Last until:
+ <br>
+ <select name="turn">
+ <option value="1">Turn 1</option>
+ <option value="2">Turn 2</option>
+ <option value="3">Turn 3</option>
+ <option value="5">Turn 4</option>
+ <option value="6">Turn 5</option>
+ <option value="7">Turn 6</option>
+ <option value="9">Turn 7</option>
+ <option value="10">Turn 8</option>
+ <option value="11">Turn 9</option>
+ <option value="13">Turn 10</option>
+ <option value="14">Turn 11</option>
+ <option value="15">Turn 12</option>
+ </select>
+ <br><br>
+
+ <div style="text-align:right">
+ <button onclick="propose_deal_cancel(event)">Cancel</button>
+ <button onclick="propose_deal_submit(event)">Submit</button>
+ </div>
+
+ </form>
+</dialog>
+
</body>
diff --git a/play.js b/play.js
index 0decf5f..76aeb9e 100644
--- a/play.js
+++ b/play.js
@@ -92,6 +92,12 @@ const turn_name = [
"Winter 1744",
]
+const DI_TURN = 0
+const DI_A_POWER = 1
+const DI_B_POWER = 2
+const DI_A_PROMISE = 3
+const DI_B_PROMISE = 4
+
const F_EMPEROR_FRANCE = 1
const F_EMPEROR_AUSTRIA = 2
const F_ITALY_FRANCE = 4
@@ -1523,11 +1529,21 @@ function on_update() {
layout_combat_marker()
}
- action_menu(document.getElementById("subsidy_menu"), [
+ window.subsidy_menu.classList.toggle("hide", is_intro())
+ action_menu(window.subsidy_menu, [
"propose_subsidy",
"cancel_subsidy",
+ "propose_deal",
])
+ update_deal_list(view.deals, window.active_deal_list, "Active Deals")
+ if (view.proposed_deal) {
+ update_deal_list([ view.proposed_deal ], window.proposed_deal_list, "Proposed Deal")
+ setTimeout(() => scroll_into_view(window.proposed_deal_list), 333)
+ } else {
+ update_deal_list(null, window.proposed_deal_list, "Proposed Deal")
+ }
+
action_button_with_argument("suit", SPADES, colorize_S)
action_button_with_argument("suit", CLUBS, colorize_C)
action_button_with_argument("suit", HEARTS, colorize_H)
@@ -1679,6 +1695,101 @@ function on_log(text) {
return p
}
+/* DEAL DIALOGS */
+
+function propose_subsidy() { send_action("propose_subsidy") }
+function cancel_subsidy() { send_action("cancel_subsidy") }
+
+function html_escape(str) {
+ return str.replaceAll("&", "&amp;").replaceAll("<", "&lt;").replaceAll(">", "&gt;")
+}
+
+function update_deal_item(deal) {
+ let [ turn, a_power, b_power, a_promise, b_promise ] = deal
+ let str = "<tr>"
+ str += "<td width=24>" + power_image[a_power]
+ str += "<td>" + html_escape(a_promise)
+ str += "<td width=24>" + power_image[b_power]
+ str += "<td>" + html_escape(b_promise)
+ str += "<td width=60>" + turn_name[turn]
+ return str
+}
+
+function update_deal_list(deals, elt, title) {
+ if (deals && deals.length > 0) {
+ let str = "<table><tr><th colspan=5>" + title
+ for (let deal of deals)
+ str += update_deal_item(deal)
+ str += "</table>"
+ elt.innerHTML = str
+ elt.style.display = "block"
+ } else {
+ elt.style.display = "none"
+ }
+}
+
+function propose_deal() {
+ if (!is_action("propose_deal"))
+ return
+
+ let form = window.propose_deal_form
+
+ form.a_power.value = view.power
+ switch (view.power) {
+ case P_FRANCE:
+ form.b_power.value = P_PRUSSIA
+ break
+ case P_PRUSSIA:
+ form.b_power.value = P_FRANCE
+ break
+ case P_PRAGMATIC:
+ form.b_power.value = P_AUSTRIA
+ break
+ case P_AUSTRIA:
+ form.b_power.value = P_PRAGMATIC
+ break
+ }
+ form.turn.value = view.turn
+
+ for (let opt of form.turn.options)
+ opt.disabled = (opt.value < view.turn)
+
+ window.propose_deal_dlog.showModal()
+}
+
+function propose_deal_submit(evt) {
+ evt.preventDefault()
+
+ let data = Object.fromEntries(new FormData(window.propose_deal_form))
+
+ data.turn = Number(data.turn)
+ data.a_power = Number(data.a_power)
+ data.b_power = Number(data.b_power)
+
+ if (!data.a_promise || !data.b_promise) {
+ alert("Each side must promise something!")
+ return
+ }
+
+ console.log(data, player_from_power(data.a_power), player_from_power(data.b_power))
+ if (player_from_power(data.a_power) === player_from_power(data.b_power)) {
+ alert("Cannot create deals between powers controlled by the same player.")
+ return
+ }
+
+ let deal = [ data.turn, data.a_power, data.b_power, data.a_promise, data.b_promise ]
+
+ if (view.actions.propose_deal)
+ send_message("action", [ "propose_deal", deal, game_cookie ])
+
+ window.propose_deal_dlog.close()
+}
+
+function propose_deal_cancel(evt) {
+ evt.preventDefault()
+ window.propose_deal_dlog.close()
+}
+
/* COMMON LIBRARY */
function array_insert(array, index, item) {
diff --git a/rules.js b/rules.js
index 9fa3eef..592d68f 100644
--- a/rules.js
+++ b/rules.js
@@ -81,6 +81,12 @@ const turn_name = [
"Winter 1744",
]
+const DI_TURN = 0
+const DI_A_POWER = 1
+const DI_B_POWER = 2
+const DI_A_PROMISE = 3
+const DI_B_PROMISE = 4
+
const F_EMPEROR_FRANCE = 1
const F_EMPEROR_AUSTRIA = 2
const F_ITALY_FRANCE = 4
@@ -1319,6 +1325,9 @@ function goto_start_turn() {
else
goto_politics()
}
+
+ // remove expired deals
+ game.deals = game.deals.filter(deal => deal[DI_TURN] < game.turn)
}
function goto_end_turn() {
@@ -1728,11 +1737,11 @@ function draw_tc(draw, n, pow) {
function give_subsidy(other) {
if (other === P_BAVARIA && is_enemy_controlled_fortress(MUNCHEN)) {
- log("Bavaria 1 TC lost (S" + MUNCHEN + " is enemy controlled)")
+ log("Bavaria TC subsidy lost\nS" + MUNCHEN + " is enemy controlled")
return
}
if (other === P_SAXONY && is_enemy_controlled_fortress(DRESDEN)) {
- log("Saxony 1 TC lost (S" + DRESDEN + " is enemy controlled)")
+ log("Saxony TC subsidy lost\nS" + DRESDEN + " is enemy controlled")
return
}
draw_tc(game.hand2[other], 1, other)
@@ -1752,9 +1761,9 @@ function goto_tactical_cards() {
game.draw = []
if (game.power === P_BAVARIA && is_enemy_controlled_fortress(MUNCHEN)) {
- log("S" + MUNCHEN + " is enemy controlled.")
+ log("Bavaria TC draw lost\nS" + MUNCHEN + " is enemy controlled.")
} else if (game.power === P_SAXONY && is_enemy_controlled_fortress(DRESDEN)) {
- log("S" + DRESDEN + " is enemy controlled.")
+ log("Saxony TC draw lost\nS" + DRESDEN + " is enemy controlled.")
} else {
let n_cards = tc_per_turn()
@@ -1764,6 +1773,48 @@ function goto_tactical_cards() {
if (map_get(game.contracts[game.power], other, 0) > 0)
--n_cards
+ // Too many subsidies to hand out!
+ // NOTE: This can only happen with Prussia.
+ // If giving subsidies to Saxony, Bavaria, and/or France
+ // while at the -1 or -2 TC on the Russia track.
+ while (n_cards < 0) {
+ // Cancel cooperative subsidy first.
+ if (map_get(game.contracts[P_PRUSSIA], P_SAXONY, 0) > 0) {
+ log("Canceled subsidy to Saxony (forced).")
+ map_delete(game.contracts[P_PRUSSIA], P_SAXONY)
+ n_cards++
+ continue
+ }
+
+ // Then the shortest of the Bavarian or France subsidy.
+ let n_france = map_get(game.contracts[P_PRUSSIA], P_FRANCE, 0)
+ let n_bavaria = map_get(game.contracts[P_PRUSSIA], P_BAVARIA, 0)
+ if (n_france > 0 && n_bavaria > 0) {
+ // Cancel the shortest remaining subsidy.
+ if (n_france > n_bavaria)
+ n_france = 0
+ else
+ n_bavaria = 0
+ }
+
+ if (n_france > 0) {
+ log("Canceled subsidy to France (forced).")
+ map_delete(game.contracts[P_PRUSSIA], P_FRANCE)
+ n_cards++
+ continue
+ }
+
+ if (n_bavaria > 0) {
+ log("Canceled subsidy to Bavaria (forced).")
+ map_delete(game.contracts[P_PRUSSIA], P_BAVARIA)
+ n_cards++
+ continue
+ }
+
+ // Should never happen!
+ n_cards = 0
+ }
+
draw_tc(game.draw, n_cards, game.power)
if (game.contracts[game.power]) {
@@ -2094,7 +2145,7 @@ states.supply_hussars = {
// put back into hand unused cards
for (let c of game.supply.pool)
- set_add(game.hand2[game.power], c) // TODO: or hand1
+ set_add(game.hand2[game.power], c)
delete game.supply.pool
delete game.supply.used
@@ -3215,7 +3266,7 @@ function end_re_enter_train() {
// put back into hand unused cards
for (let c of game.recruit.pool)
- set_add(game.hand2[game.power], c) // TODO: or hand1
+ set_add(game.hand2[game.power], c)
delete game.recruit
@@ -3531,7 +3582,7 @@ function end_recruit() {
// put back into hand unused cards
for (let c of game.recruit.pool)
- set_add(game.hand2[game.power], c) // TODO: or hand1
+ set_add(game.hand2[game.power], c)
delete game.recruit
} else {
@@ -3972,6 +4023,7 @@ function resume_retreat() {
set_active_winner()
game.state = "retreat"
} else {
+ // TODO: if mixed french/bavarian, eliminate bavarians and try again?
// eliminate if there are no retreat possibilities
delete game.retreat
game.state = "retreat_eliminate_trapped"
@@ -4760,10 +4812,10 @@ states.political_troop_power = {
view.actions.pass = 1
},
power(pow) {
- clear_undo() // reveal random cards
let info = event_troops[current_political_effect()]
set_active_to_power(pow)
if (info.tcs > 0) {
+ clear_undo() // reveal random cards
draw_tc(game.draw = [], info.tcs, game.power)
game.state = "political_troops_draw"
} else {
@@ -4814,11 +4866,13 @@ function can_add_troops() {
function goto_political_troops_place() {
let info = event_troops[current_political_effect()]
game.count = info.troops
- log(power_name[game.power] + " " + game.count + " troops.")
- if (can_add_troops())
+ if (can_add_troops()) {
+ log(power_name[game.power] + " " + game.count + " troops.")
game.state = "political_troops_place"
- else
+ } else {
+ log(power_name[game.power] + " cannot receive troops.")
next_execute_political_card()
+ }
}
states.political_troops_place = {
@@ -5106,7 +5160,7 @@ states.recruit_for_expeditionary_corps = {
prompt() {
prompt("Recruit 2 troops for expeditionary corps at a price of 8 TC-points.")
view.draw = game.recruit.pool
- if (sum_card_values(game.recruit.pool) >= 8)
+ if (sum_card_values(game.recruit.pool) >= 8 || count_cards_in_hand() === 0)
view.actions.next = 1
else
gen_cards_in_hand()
@@ -5119,7 +5173,12 @@ states.recruit_for_expeditionary_corps = {
next() {
push_undo()
- spend_card_value(game.recruit.pool, game.recruit.used, 8)
+ if (sum_card_values(game.recruit.pool) >= 8) {
+ spend_card_value(game.recruit.pool, game.recruit.used, 8)
+ } else {
+ game.recruit.used = game.recruit.pool
+ game.recruit.pool = []
+ }
log(power_name[game.power] + " spent " + game.recruit.used.map(format_card).join(", ") + ".")
@@ -5800,27 +5859,26 @@ function end_imperial_election() {
/* SUBSIDY CONTRACTS - CREATE */
-function may_create_subsidy() {
+function goto_propose_subsidy() {
+ game.proposal = { save_power: game.power, save_state: game.state, from: -1, to: -1, n: 0 }
+ game.state = "propose_subsidy_from"
+}
+
+function may_propose_subsidy_from(pow) {
if (is_two_player()) {
- let major = coop_major_power(game.power)
- if (major === P_PRAGMATIC || major === P_AUSTRIA)
+ if (pow === P_PRAGMATIC || pow === P_AUSTRIA)
return is_saxony_austrian_ally()
}
return true
}
-function goto_propose_subsidy() {
- game.proposal = { save_power: game.power, save_state: game.state, from: -1, to: -1, n: 0 }
- game.state = "propose_subsidy_from"
-}
-
states.propose_subsidy_from = {
inactive: "create subsidy contract",
prompt() {
prompt("Subsidy contract from which major power?")
- for (let from of all_major_powers)
- if (is_allied_power(game.power, from))
- gen_action_power(from)
+ for (let pow of all_major_powers)
+ if (may_propose_subsidy_from(pow))
+ gen_action_power(pow)
},
power(from) {
game.proposal.from = from
@@ -5831,15 +5889,13 @@ states.propose_subsidy_from = {
states.propose_subsidy_to = {
inactive: "create subsidy contract",
prompt() {
- let player = game.power
let from = game.proposal.from
- prompt(`Subsidy contract between ${power_name[from]} and who?`)
+ prompt(`Subsidy contract from ${power_name[from]} to who?`)
for (let to of (is_two_player() ? all_minor_powers : all_powers)) {
if (from !== to && is_allied_power(from, to)) {
if (to === P_SAXONY && is_saxony_neutral())
continue
- if (is_controlled_power(player, from) || is_controlled_power(player, to))
- gen_action_power(to)
+ gen_action_power(to)
}
}
},
@@ -5854,47 +5910,88 @@ states.propose_subsidy_length = {
prompt() {
let from = game.proposal.from
let to = game.proposal.to
- prompt(`Subsidy contract between ${power_name[from]} and ${power_name[to]} for how many turns?`)
+ prompt(`Subsidy contract from ${power_name[from]} to ${power_name[to]} for how many turns?`)
view.actions.value = [ 1, 2, 3, 4, 5, 6 ]
},
value(n) {
game.proposal.n = n
- if (is_controlled_power(game.power, game.proposal.from))
- set_active_to_power(game.proposal.to)
- else
+
+ if (false) {
+ set_active_to_power(game.proposal.from)
+ game.state = "propose_subsidy_approve_both"
+ return
+ }
+
+ let ctl_from = is_controlled_power(game.power, game.proposal.from)
+ let ctl_to = is_controlled_power(game.power, game.proposal.to)
+ if (ctl_from) {
+ if (ctl_to) {
+ end_propose_subsidy(true)
+ } else {
+ set_active_to_power(game.proposal.to)
+ game.state = "propose_subsidy_approve_last"
+ }
+ } else {
set_active_to_power(game.proposal.from)
- game.state = "propose_subsidy_approve"
+ if (ctl_to)
+ game.state = "propose_subsidy_approve_last"
+ else
+ game.state = "propose_subsidy_approve_both"
+ }
},
}
-states.propose_subsidy_approve = {
+states.propose_subsidy_approve_both = {
inactive: "approve subsidy contract",
prompt() {
let from = game.proposal.from
let to = game.proposal.to
let n = game.proposal.n
- prompt(`Subsidy contract between ${power_name[from]} and ${power_name[to]} for ${n} turns?`)
+ prompt(`Subsidy contract from ${power_name[from]} to ${power_name[to]} for ${n} turns?`)
view.actions.accept = 1
view.actions.refuse = 1
},
accept() {
- let from = game.proposal.from
- let to = game.proposal.to
- let n = game.proposal.n
- log(`Subsidy contract between ${power_name[from]} and ${power_name[to]} for ${n} turns.`)
- map_set(game.contracts[from], to, map_get(game.contracts[from], to, 0) + n)
- end_propose_subsidy()
+ if (is_controlled_power(game.power, game.proposal.to)) {
+ end_propose_subsidy(true)
+ } else {
+ set_active_to_power(game.proposal.to)
+ game.state = "prpose_subsidy_approve_last"
+ }
},
refuse() {
+ end_propose_subsidy(false)
+ },
+}
+
+states.propose_subsidy_approve_last = {
+ inactive: "approve subsidy contract",
+ prompt() {
let from = game.proposal.from
let to = game.proposal.to
let n = game.proposal.n
- log(`${power_name[from]} refused to create subsidy contract to ${power_name[to]} for ${n} turns.`)
- end_propose_subsidy()
+ prompt(`Subsidy contract from ${power_name[from]} to ${power_name[to]} for ${n} turns?`)
+ view.actions.accept = 1
+ view.actions.refuse = 1
+ },
+ accept() {
+ end_propose_subsidy(true)
+ },
+ refuse() {
+ end_propose_subsidy(false)
},
}
-function end_propose_subsidy() {
+function end_propose_subsidy(okay) {
+ let from = game.proposal.from
+ let to = game.proposal.to
+ let n = game.proposal.n
+ if (okay) {
+ log(`Accepted subsidy contract from ${power_name[from]} to ${power_name[to]} for ${n} turns.`)
+ map_set(game.contracts[from], to, n)
+ } else {
+ log(`Rejected subsidy contract from ${power_name[from]} to ${power_name[to]} for ${n} turns.`)
+ }
set_active_to_power(game.proposal.save_power)
game.state = game.proposal.save_state
delete game.proposal
@@ -5903,15 +6000,13 @@ function end_propose_subsidy() {
/* SUBSIDY CONTRACTS - CANCEL */
function may_cancel_subsidy() {
- let player = game.power
let result = false
for (let from of all_major_powers) {
map_for_each(game.contracts[from], (to, _n) => {
// cannot cancel initial contract!
if (from === P_FRANCE && to === P_BAVARIA && game.turn < 3)
return
- if (is_controlled_power(player, from) || is_controlled_power(player, to))
- result = true
+ result = true
})
}
return result
@@ -5925,15 +6020,13 @@ function goto_cancel_subsidy() {
states.cancel_subsidy_from = {
inactive: "cancel subsidy contract",
prompt() {
- let player = game.power
prompt("Cancel which subsidy contract?")
for (let from of all_major_powers) {
map_for_each(game.contracts[from], (to, _n) => {
// cannot cancel initial contract!
if (from === P_FRANCE && to === P_BAVARIA && game.turn < 3)
return
- if (is_controlled_power(player, from) || is_controlled_power(player, to))
- gen_action_power(from)
+ gen_action_power(from)
})
}
},
@@ -5946,53 +6039,146 @@ states.cancel_subsidy_from = {
states.cancel_subsidy_to = {
inactive: "cancel subsidy contract",
prompt() {
- let player = game.power
let from = game.proposal.from
- prompt(`Cancel subsidy contract between ${power_name[from]} and who?`)
+ prompt(`Cancel subsidy contract from ${power_name[from]} to who?`)
map_for_each(game.contracts[from], (to, _n) => {
// cannot cancel initial contract!
if (from === P_FRANCE && to === P_BAVARIA && game.turn < 3)
return
- if (is_controlled_power(player, from) || is_controlled_power(player, to))
- gen_action_power(to)
+ gen_action_power(to)
})
},
power(to) {
- let player = game.power
- let from = game.proposal.from
game.proposal.to = to
- if (is_controlled_power(player, from))
- set_active_to_power(to)
- else
- set_active_to_power(from)
- game.state = "cancel_subsidy_approve"
+
+ let ctl_from = is_controlled_power(game.power, game.proposal.from)
+ let ctl_to = is_controlled_power(game.power, game.proposal.to)
+ if (ctl_from) {
+ if (ctl_to) {
+ end_cancel_subsidy(true)
+ } else {
+ set_active_to_power(game.proposal.to)
+ game.state = "cancel_subsidy_approve_last"
+ }
+ } else {
+ set_active_to_power(game.proposal.from)
+ if (ctl_to)
+ game.state = "cancel_subsidy_approve_last"
+ else
+ game.state = "cancel_subsidy_approve_both"
+ }
}
}
-states.cancel_subsidy_approve = {
+states.cancel_subsidy_approve_both = {
inactive: "cancel subsidy contract",
prompt() {
let from = game.proposal.from
let to = game.proposal.to
- prompt(`Cancel subsidy contract between ${power_name[from]} and ${power_name[to]}?`)
+ prompt(`Cancel subsidy contract from ${power_name[from]} to ${power_name[to]}?`)
view.actions.accept = 1
view.actions.refuse = 1
},
accept() {
+ if (is_controlled_power(game.power, game.proposal.to)) {
+ end_cancel_subsidy(true)
+ } else {
+ set_active_to_power(game.proposal.to)
+ game.state = "cancel_subsidy_approve_last"
+ }
+ },
+ refuse() {
+ end_cancel_subsidy(false)
+ },
+}
+
+states.cancel_subsidy_approve_last = {
+ inactive: "cancel subsidy contract",
+ prompt() {
let from = game.proposal.from
let to = game.proposal.to
- log(`Canceled subsidy contract between ${power_name[from]} and ${power_name[to]}.`)
+ prompt(`Cancel subsidy contract from ${power_name[from]} to ${power_name[to]}?`)
+ view.actions.accept = 1
+ view.actions.refuse = 1
+ },
+ accept() {
+ end_cancel_subsidy(true)
+ },
+ refuse() {
+ end_cancel_subsidy(false)
+ },
+}
+
+function end_cancel_subsidy(okay) {
+ let from = game.proposal.from
+ let to = game.proposal.to
+ if (okay) {
+ log(`Canceled subsidy contract from ${power_name[from]} to ${power_name[to]}.`)
map_delete(game.contracts[from], to)
- end_cancel_subsidy()
+ } else {
+ log(`Did not cancel subsidy contract from ${power_name[from]} to ${power_name[to]}.`)
+ }
+ set_active_to_power(game.proposal.save_power)
+ game.state = game.proposal.save_state
+ delete game.proposal
+}
+
+/* NEGOTIATION - DEALS */
+
+function goto_propose_deal(deal) {
+ game.proposal = { save_power: game.power, save_state: game.state, deal }
+ let from = game.proposal.deal[DI_A_POWER]
+ set_active_to_power(from)
+ game.state = "accept_deal_from"
+}
+
+states.accept_deal_from = {
+ inactive: "accept deal",
+ prompt() {
+ let from = game.proposal.deal[DI_A_POWER]
+ let to = game.proposal.deal[DI_B_POWER]
+ prompt(`Accept ${power_name[from]} - ${power_name[to]} deal?`)
+ view.proposed_deal = game.proposal.deal
+ view.actions.accept = 1
+ view.actions.refuse = 1
+ },
+ accept() {
+ let to = game.proposal.deal[DI_B_POWER]
+ set_active_to_power(to)
+ game.state = "accept_deal_to"
},
refuse() {
- let from = game.proposal.from
- log(power_name[game.power] + ` refused to cancel subsidy contract from ${power_name[from]}.`)
- end_cancel_subsidy()
+ end_accept_deal(false)
},
}
-function end_cancel_subsidy() {
+states.accept_deal_to = {
+ inactive: "accept deal",
+ prompt() {
+ let from = game.proposal.deal[DI_A_POWER]
+ let to = game.proposal.deal[DI_B_POWER]
+ prompt(`Accept ${power_name[from]} - ${power_name[to]} deal?`)
+ view.proposed_deal = game.proposal.deal
+ view.actions.accept = 1
+ view.actions.refuse = 1
+ },
+ accept() {
+ end_accept_deal(true)
+ },
+ refuse() {
+ end_accept_deal(false)
+ },
+}
+
+function end_accept_deal(okay) {
+ let from = game.proposal.deal[DI_A_POWER]
+ let to = game.proposal.deal[DI_B_POWER]
+ if (okay) {
+ log(`Accepted ${power_name[from]} - ${power_name[to]} deal.`)
+ game.deals.push(game.proposal.deal)
+ } else {
+ log(`Rejected ${power_name[from]} - ${power_name[to]} deal.`)
+ }
set_active_to_power(game.proposal.save_power)
game.state = game.proposal.save_state
delete game.proposal
@@ -6185,6 +6371,7 @@ exports.setup = function (seed, scenario, _options) {
hand1: [ [], [], [], [], [], [] ],
hand2: [ [], [], [], [], [], [] ],
+ deals: [], // [ power, promise, turn ] tuples
contracts: [
[ P_BAVARIA, 3 ],
[],
@@ -6453,6 +6640,7 @@ exports.view = function (state, player) {
pt: total_troops_list(),
discard: total_discard_list(),
+ deals: game.deals,
contracts: game.contracts,
face_up: game.face_up,
face_down: mask_face_down(),
@@ -6497,11 +6685,13 @@ exports.view = function (state, player) {
}
// subsidy contracts actions for active player
- if (!game.proposal && !is_intro()) {
+ if (!game.proposal && !is_intro() && view.turn > 0) {
if (may_cancel_subsidy())
view.actions.cancel_subsidy = 1
- if (may_create_subsidy())
+ if (!is_intro())
view.actions.propose_subsidy = 1
+ if (!is_two_player() && !is_intro())
+ view.actions.propose_deal = 1
}
}
@@ -6523,6 +6713,9 @@ exports.action = function (state, _player, action, arg) {
} else if (action === "cancel_subsidy") {
push_undo()
goto_cancel_subsidy()
+ } else if (action === "propose_deal") {
+ push_undo()
+ goto_propose_deal(arg)
} else
throw new Error("Invalid action: " + action)
}
@@ -6606,6 +6799,8 @@ function push_undo() {
let copy = {}
for (let k in game) {
let v = game[k]
+ if (k === "deals")
+ continue
if (k === "undo")
continue
else if (k === "log")
@@ -6622,10 +6817,12 @@ function pop_undo() {
if (game.undo) {
let save_log = game.log
let save_undo = game.undo
+ let save_deals = game.deals
game = save_undo.pop()
save_log.length = game.log
game.log = save_log
game.undo = save_undo
+ game.deals = save_deals
}
}