7de675866d
release / build (push) Failing after 1m46s
runs dist.sh inside that local image via a bind mount, andcupload-image.sh pushes the already-built image. The Dockerfile also warms the Gradle dependency cache in a throwaway build stage, and pre-installs the pinned CMake version, so `run-image.sh` doesn't re-download the same Maven dependencies on every run. dist.sh now strips the -pre+meta suffix before writing package.json's version, since Pebble's build tooling parses it strictly as X.Y.Z integers and was rejecting suffixed versions.
181 lines
7.0 KiB
Markdown
181 lines
7.0 KiB
Markdown
<p align="center">
|
||
<img src="SchwertUndMagieOnPebbleCompanionApp/res/app-icon-round.png" width="290" alt="App icon">
|
||
</p>
|
||
|
||
# Schwert und Magie on Pebble
|
||
|
||
A port of the classic German C64 text-adventure RPG series **Schwert und Magie**
|
||
(German Design Group, 1989–1992) to the Pebble Time 2 smartwatch.
|
||
|
||
## Architecture
|
||
|
||
The phone runs VICE 3.8 as a companion app and streams the C64 text screen to
|
||
the watch. Button presses on the watch flow back to VICE via Bluetooth.
|
||
|
||

|
||
|
||
## The game
|
||
|
||
*Schwert und Magie* is an 8-episode text-adventure / RPG series for the
|
||
Commodore 64, published in German by boeder-Verlag. Two episodes share one
|
||
disk:
|
||
|
||
| Disk | Episodes |
|
||
|------|----------|
|
||
| I | Folge 1: Das geheimnisvolle Kraut · Folge 2: Der unheimliche Tempel |
|
||
| II | Folge 3: Das Piratenhaus · Folge 4: Die Burg des Magiers |
|
||
| III | Folge 5: Das Haus des Vampirs · Folge 6: Der Turm des Todes |
|
||
| IV | Folge 7: Unter Wasser · Folge 8: Insel der Wunder |
|
||
|
||
The copy-protection scheme asks for a word from the printed *Anleitung*
|
||
(manual). The app includes the full manual text with a look-up button (📖) so
|
||
you can answer the prompt without keeping the paper around.
|
||
|
||
## Repository layout
|
||
|
||
```
|
||
SchwertUndMagieOnPebbleWatchApp/ Pebble watchapp (C + PebbleKit JS)
|
||
SchwertUndMagieOnPebbleCompanionApp/ Android companion app (Kotlin + NDK)
|
||
versions/ Original .d64 disk images (4 disks)
|
||
docs/ Architecture notes and diagrams
|
||
build-image/ Dockerfile for the release build environment
|
||
dist/ Build artifacts (gitignored) — see dist.sh
|
||
```
|
||
|
||
Run `./dist.sh` to build release artifacts for both apps in one step:
|
||
`dist/schwert-und-magie-<version>.{aab,apk,pbw}` — the signed Android AAB
|
||
(Play Store), APK (sideload), and Pebble `.pbw` (Rebble / direct install).
|
||
Requires the Android release keystore to already be configured
|
||
(`docs/publish.md` §2.1-2.3). The version comes from the current git tag by
|
||
default (`git tag v1.2.3`); see `docs/publish.md` §4 for pushing that tag to
|
||
trigger an automated, containerized build via Gitea Actions instead.
|
||
|
||
## How it works
|
||
|
||
Three processes cooperate across two devices:
|
||
|
||
```
|
||
Pebble watch
|
||
│ Bluetooth AppMessage
|
||
▼
|
||
Core for Pebble (on phone) — PebbleKit JS bridge
|
||
│ HTTP on 127.0.0.1:8888
|
||
▼
|
||
Android companion app — NanoHTTPD server
|
||
│ JNI
|
||
▼
|
||
VICE 3.8 (C64 emulator, cross-compiled for ARM64/x86_64)
|
||
```
|
||
|
||
The watch displays the C64 text screen (40×25 cells) in a scroll view and
|
||
provides a key wheel for the number keys most used by the game. The companion
|
||
app renders VICE's 320×200 framebuffer on-screen and also provides a virtual
|
||
C64 keyboard for direct input.
|
||
|
||
See [`docs/architecture.md`](docs/architecture.md) for the full design.
|
||
|
||
## Requirements
|
||
|
||
- **Android phone** running Android 7.0+ (API 24)
|
||
- **Pebble Time 2** (or any Pebble running firmware 3.x — the `.pbw` targets
|
||
all SDK 3 platforms)
|
||
- **Core for Pebble** installed on the phone (the community Pebble app)
|
||
- **C64 ROM files** — `kernal`, `basic`, `chargen`, `1541` — legally obtained
|
||
from your own C64 or from Cloanto's C64 Forever. The app prompts you to
|
||
import them on first launch; they are never bundled.
|
||
- **Disk images** — `.d64` or `.g64` files for the four game disks. You can
|
||
import your own or use the in-app **Fetch Disks** button to download
|
||
community-preserved dumps from the Internet Archive's C64 Preservation
|
||
Project (requires nibtools, which is cross-compiled automatically).
|
||
|
||
## Building
|
||
|
||
### Android companion app
|
||
|
||
```bash
|
||
cd SchwertUndMagieOnPebbleCompanionApp
|
||
./gradlew assembleDebug # debug build
|
||
./gradlew assembleRelease # signed release build (requires keystore.properties)
|
||
./gradlew installDebug # build + install on connected device
|
||
```
|
||
|
||
VICE 3.8 and nibtools are cross-compiled automatically the first time — the
|
||
Gradle `buildVice` and `buildNibtools` tasks unpack the source tarballs from
|
||
`res/` and build `libvice.a` / `libnibtools.a` for ARM64 and x86_64. The NDK
|
||
must be installed (Android Studio → SDK Manager → SDK Tools → NDK (Side by
|
||
side)).
|
||
|
||
### Pebble watch app
|
||
|
||
```bash
|
||
cd SchwertUndMagieOnPebbleWatchApp
|
||
pebble build
|
||
pebble install --phone <phone-ip>
|
||
```
|
||
|
||
In headless / CI environments add `--vnc` to every emulator command.
|
||
|
||
## Getting disk images onto the device
|
||
|
||
**Option A — Fetch Disks button** (in-app)
|
||
Opens a dialog, downloads all 8 episode disks as `.nbz` files from the
|
||
Internet Archive C64 Preservation Project, and converts them to G64 using
|
||
nibtools. Requires a network connection; conversion runs on-device.
|
||
|
||
**Option B — manual copy**
|
||
Copy `.d64` or `.g64` files to the app's external files directory via USB or
|
||
`adb push`, matching the names expected by the drawer (e.g. `SCHWUM1A.D64`).
|
||
|
||
## Hero saves
|
||
|
||
Hero characters are stored on separate hero disks (up to 3 slots). The app
|
||
manages these from the drawer — create a new hero disk, load an episode disk,
|
||
then swap to the hero disk when the game asks for it. A built-in stat editor
|
||
lets you inspect and edit a saved hero's attributes directly.
|
||
|
||
## Save states
|
||
|
||
The 💾 button saves or restores a full VICE snapshot (CPU registers, RAM,
|
||
VICII, SID, CIA) to one of three slots. Snapshots go through a CPU trap to
|
||
ensure register consistency — see `docs/architecture.md §4.4`.
|
||
|
||
## Publishing
|
||
|
||
See [`docs/publish.md`](docs/publish.md) for keystore setup, Google Play,
|
||
F-Droid, and Rebble submission.
|
||
|
||
### Automated releases (Gitea Actions)
|
||
|
||
Pushing a tag `vX.Y.Z` builds both apps in a containerized runner and
|
||
publishes a Gitea Release with the versioned artifacts attached — see
|
||
`docs/publish.md` §4. One-time setup:
|
||
|
||
1. Build the build environment image locally and push it (`./build-image.sh`
|
||
then `./upload-image.sh`, needs `registry.env` — copy from
|
||
`registry.env.example`). Use `./run-image.sh` in between to sanity-check
|
||
the image before pushing.
|
||
2. Register a self-hosted `act_runner` with a Docker executor.
|
||
3. Add repo secrets under **Settings → Actions → Secrets**:
|
||
|
||
| Secret | Value |
|
||
|---|---|
|
||
| `RELEASE_KEYSTORE_B64` | `base64 -w0 SchwertUndMagieOnPebbleCompanionApp/release.keystore` |
|
||
| `RELEASE_KEYSTORE_PROPERTIES` | full contents of `SchwertUndMagieOnPebbleCompanionApp/keystore.properties` |
|
||
| `REGISTRY_USER` / `REGISTRY_PASSWORD` | same as in `registry.env`, so the runner can pull the private build image |
|
||
|
||
`GITEA_TOKEN` is injected automatically per job — nothing to add for it.
|
||
4. `git tag v1.2.3 && git push origin v1.2.3`.
|
||
|
||
Full details, including runner registration commands, are in
|
||
`docs/publish.md` §4.
|
||
|
||
## License
|
||
|
||
The watch app and companion app source code in this repository are released
|
||
under the **MIT License**.
|
||
|
||
The *Schwert und Magie* game content (disk images, manual text) remains the
|
||
property of its original authors and is not part of this license. VICE and
|
||
nibtools are GPLv2 and are built from source at compile time; their source
|
||
tarballs in `res/` are not covered by this repository's MIT license.
|