#!/usr/bin/env bash # Monta o Terminus (aventura de texto que ensina a linha de comando do Unix, de luffah, a partir do jogo de Michele Pratusevich e Shawn # Conrad, com a arte de Emma Tolley; GPL-2.0, com imagens MIT e musicas/sons CC0, CC-BY e CC-BY-SA) a partir do commit 52e6433 de # github.com/luffah/Terminus. O proprio sistema de build do autor (tools/build/build, Python) gera game.js e os dialogos; ele precisa de: # - o submodulo tools/lib/python3/ogaget (github.com/luffah/ogaget no commit e253684, que o tarball do GitHub nao traz) e do polib 1.2.0 # (PyPI, so Python), ambos conferidos pelo sha256; # - o "cp -rT" do GNU, que no macOS nao existe: Builds/terminus/cp-shim.sh o traduz para "cp -R origem/. destino" (so no PATH do build); # - as musicas e os sons, que o "make fetch_resources" do autor baixa do OpenGameArt: aqui cada arquivo e baixado da URL do .txt do # recurso e conferido pelo sha256 (Builds/terminus/resources.tsv; os dois zips grandes so fornecem 4 arquivos); char.wav e grl.wav # (vozes do texto, do autor) nao estao no repositorio, entao Builds/terminus/beeps.py gera dois bipes nossos com o mesmo nome. # O ingles do autor esta incompleto: terminus/en-extra.json (283 textos da interface e do jogo, mais 6 que faltavam nos dois idiomas; traducao nossa) completa o dialog.en.js. # Nao usa Node nem npm (o "-html" do autor, que gera um HTML unico, precisa deles; aqui a pagina e montada como no servidor de # desenvolvimento do autor). Mudancas nossas: index.html em ingles (dialog.en.js), com uma Content-Security-Policy e sem as # imagens de teste; so os arquivos de css do formato woff/woff2; o engine fica em js.engine/ (o index.html do autor o espera la). # # src/FredGames.Bundler/Builds/build-terminus.sh # # Saida: artifacts/build/terminus-52e6433/{terminus-52e6433-dist.tar.gz,licenses.txt}; o tar.gz tem que sair igual em dois builds. set -euo pipefail COMMIT=52e64333148ebb7e6e80da1e7582e12bbee94b43 SHA256=cb6f684e0e17c2a24164cc18cf9e698d37ef15dfbdd197537dba62f831919fc0 OGAGET=e253684e6490c26578aa19ab2a085e92c2627f4b OGAGET_SHA256=00da488fdbd4acfd75b0f412a04966eae3bc8d563e54a13dacbaec174858f334 POLIB=1.2.0 POLIB_URL=https://files.pythonhosted.org/packages/6b/99/45bb1f9926efe370c6dbe324741c749658e44cb060124f28dad201202274/polib-1.2.0-py2.py3-none-any.whl POLIB_SHA256=1c77ee1b81feb31df9bca258cbc58db1bbb32d10214b173882452c73af06d62d here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)" root="$(git -C "$here" rev-parse --show-toplevel 2>/dev/null || pwd)" out="$root/artifacts/build/terminus-${COMMIT:0:7}" cache="$root/artifacts/build/cache" mkdir -p "$cache" fetch() { # url nome sha256 if [ ! -f "$cache/$2" ]; then curl -fsSL --retry 4 "$1" -o "$cache/$2.partial" && mv "$cache/$2.partial" "$cache/$2"; fi echo "$3 $cache/$2" | shasum -a 256 -c - > /dev/null || { echo "sha256 errado: $2" >&2; exit 1; } } fetch "https://github.com/luffah/Terminus/archive/$COMMIT.tar.gz" "Terminus-${COMMIT:0:7}.tar.gz" "$SHA256" fetch "https://github.com/luffah/ogaget/archive/$OGAGET.tar.gz" "ogaget-${OGAGET:0:7}.tar.gz" "$OGAGET_SHA256" fetch "$POLIB_URL" "polib-$POLIB-py2.py3-none-any.whl" "$POLIB_SHA256" rm -rf "$out" mkdir -p "$out/tree" "$out/polib" tar -xzf "$cache/Terminus-${COMMIT:0:7}.tar.gz" -C "$out/tree" --strip-components 1 mkdir -p "$out/tree/tools/lib/python3/ogaget" tar -xzf "$cache/ogaget-${OGAGET:0:7}.tar.gz" -C "$out/tree/tools/lib/python3/ogaget" --strip-components 1 unzip -q -o "$cache/polib-$POLIB-py2.py3-none-any.whl" -d "$out/polib" # musicas e sons cd "$out/tree" while IFS=$'\t' read -r target cname url sha member; do case "$target" in '#'*|'') continue ;; esac fetch "$url" "$cname" "$sha" mkdir -p "$(dirname "game_art/$target")" if [ "$member" = "-" ]; then cp "$cache/$cname" "game_art/$target"; else python3 -I -c 'import sys,zipfile; sys.stdout.buffer.write(zipfile.ZipFile(sys.argv[1]).read(sys.argv[2]))' "$cache/$cname" "$member" > "game_art/$target"; fi done < "$here/terminus/resources.tsv" python3 -I "$here/terminus/beeps.py" game_art/sound # Mudancas de texto nossas: o unico texto em frances no codigo do engine (o rotulo do ".." no ls) e duas notas de desenvolvimento do autor, # em frances, dentro de salas do jogo (a de "future:capital" fala da coluna Vendome; a do "trollcave" e um lembrete de programacao). python3 -I - <<'PY' p = 'engine/js/commands/ls.js' s = open(p, encoding='utf-8').read() assert "' (revenir sur tes pas)'" in s open(p, 'w', encoding='utf-8').write(s.replace("' (revenir sur tes pas)'", "' (go back)'")) PY rm "game/terminus/rootfs/var/townsquare/brokenbridge/clearing/ominouspath/hidden:trollcave/note.txt" "game/terminus/rootfs/var/future:capital/place_vendome/imperial_tour/note.txt" # build do autor (sem Node): game.js e dialog..js em _build/terminus mkdir -p "$out/shim" && cp "$here/terminus/cp-shim.sh" "$out/shim/cp" PATH="$out/shim:$PATH" PYTHONPATH="$out/polib" python3 tools/build/build game/terminus _build/terminus > "$out/build.log" 2>&1 || { tail -20 "$out/build.log"; exit 1; } b=_build/terminus [ -s $b/js.built/game.js ] && [ -s $b/js.built/dialog.en.js ] && [ -d $b/img ] && [ -d $b/snd ] # pagina: como o servidor de desenvolvimento do autor (game/terminus/webroot), em ingles d="$out/dist" mkdir -p "$d/css" "$d/js.built" cp -R game/terminus/webroot/js "$d/js" cp -R engine/js "$d/js.engine" cp $b/js.built/game.js "$d/js.built/" # O ingles do autor esta incompleto (faltam 283 dos 456 textos e mais 6 nos dois idiomas, quase todos da interface e das partes novas, e alguns estao em frances): # terminus/en-extra.json traz a traducao nossa dessas chaves, acrescentada ao fim do dialog.en.js. python3 -I - "$b/js.built/dialog.en.js" "$here/terminus/en-extra.json" "$d/js.built/dialog.en.js" <<'PY' import json, sys src, extra, dst = sys.argv[1:4] s = open(src, encoding='utf-8').read().rstrip('\n') x = json.load(open(extra, encoding='utf-8')) js = json.dumps(x, ensure_ascii=True) open(dst, 'w', encoding='utf-8').write(s + '\n// FredyGames: English text missing in the original (en-extra.json)\n;(function () { var x = ' + js + '; for (var k in x) { dialog[k] = x[k]; } })();\n') PY cp -R $b/img "$d/img" cp -R $b/snd "$d/snd" cp game/terminus/webroot/css/terminus.css game/terminus/webroot/css/*.woff game/terminus/webroot/css/*.woff2 "$d/css/" # em janelas estreitas (< 1024 px) o campo de texto escondido (mais largo que a janela) rola a pagina na horizontal ao receber o foco e corta o # texto a esquerda; o container passa a cortar (overflow: clip, que nem o foco consegue rolar) o que passa dele (so nessa largura, onde ele ocupa a janela inteira) printf '\n/* FredyGames: in narrow windows the hidden input made the page scroll sideways and cut the text */\n@media all and (max-width: 1023px) { html, body, #desktop, #container { overflow: clip; } }\n' >> "$d/css/terminus.css" python3 -I - "$d" game/terminus/webroot/index.html <<'PY' import sys d, src = sys.argv[1], sys.argv[2] s = open(src, encoding='utf-8').read() assert 'js.built/dialog.fr.js' in s s = s.replace('js.built/dialog.fr.js', 'js.built/dialog.en.js') csp = '\n ' s = s.replace('&2; then echo "o build ainda cita um servico de terceiros" >&2; exit 1; fi # licencas e creditos { echo "== Terminus (LICENSE.md do repositorio, GNU General Public License versao 2)" cat LICENSE.md echo echo "== Creditos do jogo (game/terminus/credits.txt)" cat game/terminus/credits.txt echo echo "== Licenca MIT das imagens do jogo original (cada arquivo .txt de imagem diz 'license: mit', artist 'Emma Tolley & Shawn Conrad'; o repositorio nao traz o texto)" cat "$here/terminus/mit-art.txt" echo echo "== Recursos servidos (de game_art/, com os arquivos .txt do repositorio)" python3 -I "$here/terminus/credits.py" "$out/tree" "$d" echo "== howler.js 2.0.4 (js.engine/addons/outsiders/howler.core.js, MIT: Copyright (c) 2013-2017 James Simpson and GoldFire Studios, Inc.)" echo "Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the \"Software\"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. THE SOFTWARE IS PROVIDED \"AS IS\", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE." echo echo "== Terminal Grotesque (css/terminal-grotesque-webfont.woff2 e .woff; Copyright (c) 2011 Raphael Bastide, with Reserved Font Name Terminal Grotesque; SIL Open Font License 1.1)" cat "$here/terminus/ofl-1.1.txt" } > "$out/licenses.txt" find "$d" -exec touch -t 202611040000 {} + ( cd "$out" && find dist -type f | LC_ALL=C sort > files.txt \ && COPYFILE_DISABLE=1 tar --format=ustar --uid 0 --gid 0 --uname root --gname root -n -cf - -T files.txt \ | gzip -n -9 > "terminus-${COMMIT:0:7}-dist.tar.gz" && rm files.txt ) du -sh "$d" cd "$out" && rm -rf tree polib shim ls -l "$out/terminus-${COMMIT:0:7}-dist.tar.gz" shasum -a 256 "$out/terminus-${COMMIT:0:7}-dist.tar.gz" "$out/licenses.txt"