diff options
| author | Florian Fischer <florian.fischer@muhq.space> | 2025-06-08 20:34:11 -0500 |
|---|---|---|
| committer | Florian Fischer <florian.fischer@muhq.space> | 2025-08-20 15:57:19 +0200 |
| commit | 4223ee27c9d83d5ba71870233ee32655ccbf3ec6 (patch) | |
| tree | bdca9b0554c376b3d6818d7c732cb315a2f9503f /html | |
| parent | eec6cf18c8d6081b8b956de2f42e81084f6f747e (diff) | |
| download | muhqs-game-4223ee27c9d83d5ba71870233ee32655ccbf3ec6.tar.gz muhqs-game-4223ee27c9d83d5ba71870233ee32655ccbf3ec6.zip | |
add boss overview pages
Diffstat (limited to 'html')
| -rw-r--r-- | html/Makefile | 26 | ||||
| -rw-r--r-- | html/boss/ai-companion.html | 184 | ||||
| -rw-r--r-- | html/boss/index.md | 10 | ||||
| -rw-r--r-- | html/maps.md | 10 |
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" +::: |
