summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--rules.js242
1 files changed, 238 insertions, 4 deletions
diff --git a/rules.js b/rules.js
index 9e262dd..9c795a7 100644
--- a/rules.js
+++ b/rules.js
@@ -13,16 +13,250 @@ const DS = 0
const BK = 1
const VE = 2
-// Faction names
+const faction_name = [ "Delhi Sultanate", "Bahmani Kingdom", "Vijayanagara Empire" ]
+
+// Role names
const NAME_DS = "DS"
const NAME_BK = "BK"
const NAME_VE = "VE"
+const NAME_SOLO = "Solo"
-const faction_name = [ "Delhi Sultanate", "Bahmani Kingdom", "Vijayanagara Empire" ]
+exports.scenarios = [ "Standard", "Solo" ]
+
+exports.roles = function (scenario, _options) {
+ if (scenario === "Solo")
+ return [ NAME_SOLO ]
+ return [ NAME_DS, NAME_BK, NAME_VE ]
+}
+
+function is_current_role(role) {
+ if (role === NAME_SOLO) return true
+ if (role === NAME_DS) return game.current === DS
+ if (role === NAME_BK) return game.current === BK
+ if (role === NAME_VE) return game.current === VE
+ return false
+}
+
+function load_game(state) {
+ game = state
+}
+
+function save_game() {
+ if (game.solo) {
+ game.active = NAME_SOLO
+ return game
+ }
+ if (game.current === DS)
+ game.active = NAME_DS
+ if (game.current === BK)
+ game.active = NAME_BK
+ if (game.current === VE)
+ game.active = NAME_VE
+ return game
+}
+
+exports.view = function (state, role) {
+ load_game(state)
+
+ let this_card = game.deck[0] | 0
+ let deck_size = Math.max(0, game.deck.length - 1)
+
+ view = {
+ prompt: null,
+ actions: null,
+ log: game.log,
+ current: game.current,
+ deck: [ this_card, deck_size ],
+ }
+
+ if (game.result) {
+ view.prompt = game.victory
+ } else if (!is_current_role(role)) {
+ let inactive = states[game.state].inactive
+ if (!inactive) {
+ if (game.vm)
+ inactive = "Event"
+ else
+ inactive = game.state
+ }
+ view.prompt = `Waiting for ${faction_name[game.current]} \u2014 ${inactive}.`
+ } else {
+ view.actions = {}
+
+ if (states[game.state])
+ states[game.state].prompt()
+ else
+ view.prompt = "Unknown state: " + game.state
+
+ if (states[game.state] && !states[game.state].disable_negotiation) {
+ view.actions.ask_resources = 1
+ if (game.resources[game.current] > 0)
+ view.actions.transfer_resources = 1
+ else
+ view.actions.transfer_resources = 0
+ if (game.cavalry[game.current] > 0)
+ view.actions.transfer_cavalry = 1
+ else
+ view.actions.transfer_cavalry = 0
+ if (true) // TODO: can_ask_cavalry()
+ view.actions.ask_cavalry = 1
+ else
+ view.actions.ask_cavalry = 0
+ }
+
+ if (view.actions.undo === undefined) {
+ if (game.undo && game.undo.length > 0)
+ view.actions.undo = 1
+ else
+ view.actions.undo = 0
+ }
+ }
+
+ save_game()
+ return view
+}
+
+exports.action = function (state, role, action, arg) {
+ load_game(state)
+ let S = states[game.state]
+ if (S && action in S) {
+ S[action](arg)
+ } else {
+ if (action === "undo" && game.undo && game.undo.length > 0)
+ pop_undo()
+ else if (action === "ask_resources")
+ action_ask_resources()
+ else if (action === "ask_cavalry")
+ action_ask_cavalry()
+ else if (action === "transfer_resources")
+ action_transfer_resources()
+ else if (action === "transfer_cavalry")
+ action_transfer_cavalry()
+ else
+ throw new Error("Invalid action: " + action)
+ }
+ return save_game()
+}
+
+/* SETUP */
+
+exports.setup = function (seed, scenario, _options) {
+ game = {
+ seed,
+ log: [],
+ undo: [],
+ active: null,
+ current: 0,
+ state: null,
+
+ // TODO: control, pieces, and tracks
+ deck: [],
+ }
+
+ if (scenario === "Solo")
+ game.solo = 1
+
+ // TODO: setup start pieces
+
+ // goto_card()
+
+ game.current = DS
+ game.state = "todo"
+
+ return save_game()
+}
+
+/* LOGGING */
+
+function log(msg) {
+ game.log.push(msg)
+}
+
+function logi(msg) {
+ log(">" + msg)
+}
+
+function log_br() {
+ if (game.log.length > 0 && game.log[game.log.length - 1] !== "")
+ game.log.push("")
+}
+
+function log_h1(msg) {
+ log_br()
+ log(".h1 " + msg)
+ log_br()
+}
+
+function log_h2(msg) {
+ log_br()
+ log(".h2 " + msg)
+ log_br()
+}
+
+function log_action(msg) {
+ log_br()
+ log(msg)
+}
+
+function log_transfer(msg) {
+ log_br()
+ log(".n " + msg)
+ log_br()
+}
+
+function log_transfer_resources(from, to, n) {
+ log_transfer(`${faction_name[from]} gave ${n} Resources to ${faction_name[to]}.`)
+}
-exports.roles = [ NAME_DS, NAME_BK, NAME_VE ]
+function log_space(s, action) {
+ if (action)
+ log_action("S" + s + " - " + action)
+ else
+ log_action("S" + s)
+}
+
+function push_summary() {
+ if (game.summary)
+ throw "TOO MANY SUMMARIES"
+ game.summary = []
+}
+
+function log_summary(msg) {
+ for (let item of game.summary) {
+ if (item[1] === msg) {
+ item[0]++
+ return
+ }
+ }
+ game.summary.push([1, msg])
+}
-exports.scenarios = [ "Standard" ]
+function pop_summary() {
+ if (game.summary.length > 0) {
+ for (let [n, msg] of game.summary) {
+ log(">" + msg.replace("%", String(n)))
+ }
+ } else {
+ log(">Nothing")
+ }
+ game.summary = null
+}
+
+function log_summary_place(p) {
+ let from = piece_space(p)
+ if (from !== AVAILABLE)
+ log_summary("% " + piece_name(p) + " from S" + from)
+ else
+ log_summary("% " + piece_name(p))
+}
+
+function log_summary_move_to_from(p, to) {
+ log_summary("% " + piece_name(p) + " to S" + to + " from S" + piece_space(p))
+}
+
+function log_summary_remove(p) {
+ log_summary("Removed % " + piece_name(p))
+}
/* COMMON LIBRARY */