diff options
-rw-r--r-- | rules.js | 242 |
1 files changed, 238 insertions, 4 deletions
@@ -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 */ |