diff options
author | Tor Andersson <tor@ccxvii.net> | 2024-10-29 17:48:51 +0100 |
---|---|---|
committer | Tor Andersson <tor@ccxvii.net> | 2024-10-29 17:49:15 +0100 |
commit | 61dcf972cecd41e6bfe459725414f5b2c15c4bdc (patch) | |
tree | b5a0a02ab0dfefd4eb067a29c742f1cb0d8677c7 | |
download | land-and-freedom-61dcf972cecd41e6bfe459725414f5b2c15c4bdc.tar.gz |
Initial commit.
-rw-r--r-- | about.html | 13 | ||||
-rw-r--r-- | create.html | 0 | ||||
-rw-r--r-- | play.html | 49 | ||||
-rw-r--r-- | play.js | 88 | ||||
-rw-r--r-- | rules.js | 108 | ||||
-rw-r--r-- | title.sql | 1 |
6 files changed, 259 insertions, 0 deletions
diff --git a/about.html b/about.html new file mode 100644 index 0000000..526e01e --- /dev/null +++ b/about.html @@ -0,0 +1,13 @@ +<p> +Lorem ipsum dolor... + +<p> +Design: Alex Knight. +<br> +Published by <a href="https://www.bluepantherllc.com/products/land-and-freedom">Blue Panther</a>. +<br> +Programming © 2024 by Frans Bongers. + +<ul> +<li><a href="/land-and-freedom/info/rules.html">Rulebook</a> +</ul> diff --git a/create.html b/create.html new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/create.html diff --git a/play.html b/play.html new file mode 100644 index 0000000..ea74288 --- /dev/null +++ b/play.html @@ -0,0 +1,49 @@ +<!DOCTYPE html> +<!-- vim:set nowrap: --> +<html lang="en"> +<head> +<meta name="viewport" content="width=device-width, height=device-height, user-scalable=no, interactive-widget=resizes-content, viewport-fit=cover"> +<meta name="theme-color" content="#444"> +<meta charset="UTF-8"> +<title>LAND & FREEDOM</title> +<link rel="icon" href="favicon.png"> +<link rel="stylesheet" href="/fonts/fonts.css"> +<link rel="stylesheet" href="/common/client.css"> +<script defer src="/common/client.js"></script> +<script defer src="play.js"></script> +</head> +<style> +/* insert stylesheet here */ +</style> +<body> + +<header> + <div id="toolbar"> + <details> + <summary><img src="/images/cog.svg"></summary> + <menu> + <li><a href="info/rules.html" target="_blank">Rules</a> + </menu> + </details> + </div> +</header> + +<aside> + <div id="roles"> + </div> + <div id="log"></div> +</aside> + +<main> + <div id="mapwrap"> + <div id="map"> + <div id="spaces"></div> + <div id="pieces"></div> + </div> + </div> + <div id="hand"></div> +</main> + +<footer id="status"></footer> + +</body> @@ -0,0 +1,88 @@ +"use strict" + +/* global view, player, send_action, action_button */ + +const SPACE_COUNT = 64 +const PIECE_COUNT = 32 +const CARD_COUNT = 52 + +let ui = { + map: document.getElementById("map"), + hand: document.getElementById("hand"), + spaces: [], + pieces: [], + cards: [], +} + +let action_register = [] + +function register_action(e, action, id) { + e.my_action = action + e.my_id = id + e.onmousedown = on_click_action + action_register.push(e) +} + +function on_click_action(evt) { + if (evt.button === 0) + if (send_action(evt.target.my_action, evt.target.my_id)) + evt.stopPropagation() +} + +function is_action(action, arg) { + if (arg === undefined) + return !!(view.actions && view.actions[action] === 1) + return !!(view.actions && view.actions[action] && view.actions[action].includes(arg)) +} + +let on_init_once = false + +function on_init() { + if (on_init_once) + return + on_init_once = true + + // create space elements + for (let s = 0; s < SPACE_COUNT; ++s) { + let e = ui.spaces[s].document.createElement("div") + e.className = "space" + register_action(e, "space", s) + ui.map.appendChild(e) + } + + // create piece elements + for (let p = 0; p < PIECE_COUNT; ++p) { + let e = ui.pieces[p] = document.createElement("div") + e.className = "piece" + register_action(e, "piece", s) + } + + // create card elements + for (let c = 0; c < CARD_COUNT; ++c) { + let e = ui.cards[c] = document.createElement("div") + e.className = "card" + register_action(e, "card", s) + } +} + +function on_update() { + on_init() + + for (let s = 0; s < SPACE_COUNT; ++s) + ui.spaces[s].replaceChildren() + + for (let p = 0; p < PIECE_COUNT; ++p) { + let s = view.location[p] + ui.spaces[s].appendChild(ui.pieces[p]) + } + + ui.hand.replaceChildren() + for (let c of view.hand) + ui.hand.appendChild(ui.cards[c]) + + for (let e of action_register) + e.classList.toggle("action", is_action(e.my_action, e.my_id)) + + action_button("next", "Next") + action_button("undo", "Undo") +} diff --git a/rules.js b/rules.js new file mode 100644 index 0000000..08edea8 --- /dev/null +++ b/rules.js @@ -0,0 +1,108 @@ +"use strict" + +var states = {} +var game = null +var view = null + +exports.scenarios = [ "Standard" ] + +exports.roles = [ "Anarchist", "Moderate", "Fascist" ] + +function gen_action(action, argument) { + if (!(action in view.actions)) + view.actions[action] = [] + view.actions[action].push(argument) +} + +function gen_action_space(space) { + gen_action("space", space) +} + +function gen_action_piece(piece) { + gen_action("piece", piece) +} + +function gen_action_card(card) { + gen_action("card", card) +} + +exports.action = function (state, player, action, arg) { + game = state + let S = states[game.state] + if (action in S) + S[action](arg, player) + else if (action === "undo" && game.undo && game.undo.length > 0) + pop_undo() + else + throw new Error("Invalid action: " + action) + return game +} + +exports.view = function (state, player) { + game = state + + view = { + log: game.log, + prompt: null, + location: game.location, + selected: game.selected, + } + + if (player !== game.active) { + let inactive = states[game.state].inactive || game.state + view.prompt = `Waiting for ${game.active} to ${inactive}.` + } else { + view.actions = {} + states[game.state].prompt() + if (game.undo && game.undo.length > 0) + view.actions.undo = 1 + else + view.actions.undo = 0 + } + + return view +} + +exports.setup = function (seed, scenario, options) { + game = { + seed: seed, + state: null, + active: "Anarchist", + log: [], + undo: [], + } + + game.state = "move" + + return game +} + +states.move = { + inactive: "move", + prompt() { + view.prompt = "Move a piece." + for (let p = 0; p < 32; ++p) + gen_action_piece(p) + }, + piece(p) { + game.selected = p + game.state = "move_to" + }, +} + +states.move_to = { + inactive: "move", + prompt() { + view.prompt = "Move the piece to a space." + for (let s = 0; s < 64; ++s) + gen_action_space(s) + }, + space(to) { + game.location[game.selected] = to + game.state = "move" + if (game.active === PLAYER1) + game.active = PLAYER2 + else + game.active = PLAYER1 + }, +} diff --git a/title.sql b/title.sql new file mode 100644 index 0000000..c6dfb22 --- /dev/null +++ b/title.sql @@ -0,0 +1 @@ +insert or ignore into titles ( title_id, title_name, bgg, is_symmetric ) values ( 'land-and-freedom', 'Land and Freedom', 375931, 0 ); |