aboutsummaryrefslogtreecommitdiff
path: root/html
diff options
context:
space:
mode:
authorFlorian Fischer <florian.fischer@muhq.space>2025-06-08 20:34:11 -0500
committerFlorian Fischer <florian.fischer@muhq.space>2025-07-03 22:01:22 -0400
commit27f2934a62030eaf1bf6cc1f7f34802d3e1b86f3 (patch)
tree66ec0ade0d9aa4b63a697d20f3eee327759ebfdd /html
parentb9cb10d93c802280f4bc7f9cb42bb6b596edcf10 (diff)
downloadmuhqs-game-27f2934a62030eaf1bf6cc1f7f34802d3e1b86f3.tar.gz
muhqs-game-27f2934a62030eaf1bf6cc1f7f34802d3e1b86f3.zip
add boss overview pages
Diffstat (limited to 'html')
-rw-r--r--html/Makefile26
-rw-r--r--html/boss/ai-companion.html184
-rw-r--r--html/boss/index.md10
-rw-r--r--html/maps.md10
4 files changed, 223 insertions, 7 deletions
diff --git a/html/Makefile b/html/Makefile
index 3519a80b..108a7fc6 100644
--- a/html/Makefile
+++ b/html/Makefile
@@ -45,8 +45,14 @@ EN_CARDS_LISTING := en/$(CARDS_LISTING)
LANG_CARDS_LISTINGS := $(foreach card_listing, $(DE_CARDS_LISTING) $(EN_CARDS_LISTING), \
$(addprefix $(BUILDDIR)/, $(card_listing:.md=.html)))
-SITES := index.md rules.md cards.md maps.md tools.html decks.md
-HTML := $(addprefix $(BUILDDIR)/,$(SITES:.md=.html))
+GENERATE_BOSS := $(GAME_ROOT)/scripts/generate_boss_html.py
+
+BOSSES := kraken tyrant
+BOSS_SITES := $(addprefix boss/,$(BOSSES:=.html))
+BOSS_SITES_HTML := $(addprefix $(BUILDDIR)/,$(BOSS_SITES))
+
+SITES := index.md rules.md cards.md maps.md tools.html decks.md boss/ai-companion.html boss/index.html
+HTML := $(addprefix $(BUILDDIR)/,$(SITES:.md=.html)) $(BOSS_SITES_HTML)
BLOG_SOURCEDIR := $(HTML_ROOT)/blog
BLOG_POSTS_MD := $(shell find $(BLOG_SOURCEDIR) -mindepth 1 -type f -name "*.md" -printf "%f\n")
@@ -66,7 +72,7 @@ FILES_TO_COPY_TARGETS := $(addprefix $(BUILDDIR)/,$(FILES_TO_COPY))
all: $(HTML) $(RULES_HTML) maps misc $(BLOG_POSTS_HTML)
misc: $(BUILDDIR)/latex-build $(BUILDDIR)/cards-data $(FILES_TO_COPY_TARGETS) \
- $(BUILDDIR)/webtools.wasm \
+ $(BUILDDIR)/webtools.wasm $(BUILDDIR)/boss/ai-companion.wasm \
$(BUILDDIR)/feed.rss
wasm_exec.js: $(shell go env GOROOT)/lib/wasm/wasm_exec.js
@@ -138,9 +144,23 @@ $(eval $(call generateHtml, $(BUILDDIR),))
$(eval $(call generateRulesHtml, $(BUILDDIR)/rules, -N))
$(eval $(call generateHtml, $(BUILDDIR)/blog,))
+CARDS = $(notdir $(basename $(wildcard $(BUILDDIR)/cards-data/*/*.yml)))
+GENCARDSDATALIST := echo $(CARDS) | python -c 'import sys; print("".join([f"<option value=\"{card}\"></option>" for card in sys.stdin.read().split()]))'
+CARDSDATALIST := $(shell $(GENCARDSDATALIST))
+$(BUILDDIR)/boss/ai-companion.html: boss/ai-companion.html $(MAKEFILE_LIST)
+ @echo "building $@"
+ $(VERBOSE)if test \( ! \( -d $(@D) \) \); then mkdir -p $(@D); fi
+ $(VERBOSE) sed 's|%CARDS%|$(CARDSDATALIST)|' $< > $@
+
FEEDSRC = feed
GEN_FEED = $(FEEDSRC)/create_feed.py
FEEDITEMS = $(wildcard $(FEEDSRC)/items/*)
$(BUILDDIR)/feed.rss: $(FEEDITEMS) $(GEN_FEED)
+ @echo "building $$@"
$(VERBOSE)python3 $(GEN_FEED) $(FEEDITEMS) > $@
+
+$(BOSS_SITES_HTML): $(BUILDDIR)/boss/%.html: $(MAKEFILE_LIST) $(GENERATE_BOSS) $(GENERATE_HOVER_LINKS)
+ @echo "building $@"
+ @if test \( ! \( -d $(@D) \) \); then mkdir -p $(@D); fi
+ $(VERBOSE)$(GENERATE_BOSS) $(*F) $(DATA_ROOT) $(MAPS_ROOT) $(RULES_ROOT) > $@
diff --git a/html/boss/ai-companion.html b/html/boss/ai-companion.html
new file mode 100644
index 00000000..65923543
--- /dev/null
+++ b/html/boss/ai-companion.html
@@ -0,0 +1,184 @@
+<!doctype html>
+<html>
+<head>
+ <meta charset="utf-8">
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, user-scalable=yes" />
+ <title>AI Companion</title>
+
+ <script src="https://cdnjs.cloudflare.com/ajax/libs/eruda/3.4.1/eruda.js" integrity="sha512-3h7ROKDcr6JDuNeJM83xKEnx4cqMvii81NQ+9bSOwOTQL6AKhSmp5oVRL1R4rrM6H23CarCgDK3FIFl3ZnZEZA==" crossorigin="anonymous" referrerpolicy="no-referrer"></script>
+ <script>eruda.init();</script>
+
+ <script src="../js/wasm_exec.js"></script>
+
+ <style>
+:root {
+ /* define applied colors */
+ --bg: #fdfdfd;
+ --fg: #1a1a1a;
+}
+
+@media (prefers-color-scheme: dark) {
+ /* change apllied colors to the dark gruvbox pallet
+ * https://github.com/morhetz/gruvbox
+ */
+ :root {
+ --bg: #282828; /* dark bg */
+ --fg: #ebdbb2; /* dark fg */
+ }
+}
+
+html {
+ line-height: 1.5;
+ font-family: Georgia, serif;
+ font-size: 20px;
+ color: var(--fg);
+ background-color: var(--bg);
+}
+
+body {
+ margin: 0 auto;
+ max-width: 36em;
+ padding-left: 50px;
+ padding-right: 50px;
+ padding-top: 50px;
+ padding-bottom: 50px;
+ hyphens: auto;
+ word-wrap: break-word;
+ text-rendering: optimizeLegibility;
+ font-kerning: normal;
+}
+
+@media (max-width: 600px) {
+ body {
+ font-size: 0.9em;
+ padding: 1em;
+ }
+}
+.card-remove-button {
+ margin: 5px;
+ border: solid;
+ border-radius: 1px;
+ background: gray;
+}
+</style>
+
+ <datalist id="maps">
+ <option value="the-kraken"></option>
+ <option value="the-tyrant"></option>
+ </datalist>
+ <datalist id="cards">
+ %CARDS%
+ </datalist>
+
+ <script>
+ if (!WebAssembly.instantiateStreaming) { // polyfill
+ WebAssembly.instantiateStreaming = async (resp, importObject) => {
+ const source = await (await resp).arrayBuffer();
+ return await WebAssembly.instantiate(source, importObject);
+ };
+ }
+
+ const go = new Go();
+ let mod, inst;
+ const wasm = "ai-companion.wasm"
+
+ WebAssembly.instantiateStreaming(fetch(wasm), go.importObject).then((result) => {
+ mod = result.module;
+ inst = result.instance;
+ document.getElementById("runButton").disabled = false;
+ }).catch((err) => {
+ console.error(err);
+ });
+
+ var cards = {};
+ for (const opt of document.getElementById("cards").options) {
+ cards[opt.value] = true;
+ }
+
+ var players = {};
+
+ var ebitenArgs;
+ async function run() {
+ const map = document.getElementById("mapInput").value;
+ // global value retrieved by the go wasm
+ ebitenArgs = JSON.stringify({mapName: map, players: players.values});
+ await go.run(inst);
+ inst = await WebAssembly.instantiate(mod, go.importObject); // reset instance
+ }
+
+ function addCard(cardInput) {
+ const card = cardInput.value;
+ if (!cards[card]) return;
+ let playerDisplay = cardInput.parentNode;
+ const playerName = playerDisplay.id.slice(0, -4);
+ let player = players[playerName];
+ let pcards = player.cards;
+
+ console.log(playerName + " " + card);
+ pcards.push(card);
+ const cardIdx = pcards.length;
+
+ let cardElem = document.createElement("div");
+ cardElem.appendChild(document.createTextNode(card));
+ let rmvBtn = document.createElement("span");
+ rmvBtn.innerHTML = "x";
+ rmvBtn.onclick = function() {
+ pcards.splice(cardIdx, 1);
+ playerDisplay.removeChild(cardElem);
+ };
+ rmvBtn.classList.add("card-remove-button");
+ cardElem.appendChild(rmvBtn);
+ playerDisplay.appendChild(cardElem);
+ }
+
+ function addPlayer() {
+ let nameInput = document.getElementById("playerName");
+ const name = nameInput.value;
+ players[name] = {name: name, cards: []}
+
+ nameInput.value = "";
+
+ let player = document.createElement("div");
+ player.id = name;
+ player.innerHTML = `${name}
+<div id="${name}Deck">
+<input list="cards" oninput="addCard(this)">
+</input>
+</div>`;
+ document.getElementById("players").appendChild(player);
+ }
+
+ function prefillInputsFromUrl() {
+ const queryParams = window.location.search.substring(1).split("?");
+ for (const param of queryParams) {
+ let parts = param.split("=")
+ let key = parts[0]
+ let value = parts[1]
+
+ let input = document.getElementById(key);
+ if (input) {
+ input.value = value;
+ }
+ }
+ }
+window.onload = function() {
+ prefillInputsFromUrl();
+}
+ </script>
+</head>
+
+<body>
+ <h1>AI Companion</h1>
+ <label for="mapInput">Map:</label>
+ <input autocomplete="on" id="mapInput" list="maps"></input>
+ <br>
+
+ <label for="playerName">Player name:</label>
+ <input id="playerName"></input>
+ <button onclick="addPlayer()">add</button>
+
+ <div id="players"></div>
+
+ <button onClick="run();" id="runButton" disabled>Run</button>
+</body>
+</html>
diff --git a/html/boss/index.md b/html/boss/index.md
new file mode 100644
index 00000000..ec3c7776
--- /dev/null
+++ b/html/boss/index.md
@@ -0,0 +1,10 @@
+%Bosses
+
+For muhq's game there exist multiple [maps](../maps.html#coop) offering a cooperative game experience battling an AI opponent.
+
+## Available Bosses
+
+The following Bosses are available:
+
+* The Kraken - a simple AI opponent [[map](../maps.html#the-kraken)] [[overview](kraken.html)] [[ai-companion](ai-companion.html?mapInput=the-kraken)]
+* The Tyrant - a sophisticated AI altering the map [[map](../maps.html#the-tyrant)] [[overview](tyrant.html)] [[ai-companion](ai-companion.html?mapInput=the-tyrant)]
diff --git a/html/maps.md b/html/maps.md
index 8eda748c..1a9b2c9d 100644
--- a/html/maps.md
+++ b/html/maps.md
@@ -4,10 +4,10 @@ Tile definitions can be found in the [rules](rules.html)
## Available Maps
-### Coop
+### Coop vs. an AI [*Boss*](boss/)
-* The Kraken [[yaml](maps/the-kraken.yml)] [[png](maps/the-kraken.png)]
-* The Tyrant [[yaml](maps/the-tyrant.yml)] [[png](maps/the-tyrant.png)]
+* The Kraken [[yaml](maps/the-kraken.yml)] [[png](maps/the-kraken.png)] [[boss](boss/kraken.html)]
+* The Tyrant [[yaml](maps/the-tyrant.yml)] [[png](maps/the-tyrant.png)] [[boss](boss/tyrant.html)]
### 2 Players
@@ -22,4 +22,6 @@ Tile definitions can be found in the [rules](rules.html)
* Islands [[yaml](maps/4P-islands.yml)] [[png](maps/4P-islands.png)]
-"Dolle karte die leg ich mal da hin"
+:::{lang=de}
+ "Dolle Karte, die leg ich mal da hin"
+:::