Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 10 additions & 0 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,16 @@ jobs:
DOTNET_CLI_TELEMETRY_OPTOUT: true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
submodules: recursive

# The rules come from the engine submodule. Without it, restore fails with a puzzling missing-project error.
- name: Engine submodule
run: |
if [ ! -f external/puzzle-boy-engine/src/PuzzleBoy.Rules/PuzzleBoy.Rules.csproj ]; then
echo "::error::external/puzzle-boy-engine is empty. Check out with submodules, or run: git submodule update --init"
exit 1
fi

- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
Expand Down
10 changes: 10 additions & 0 deletions .github/workflows/release.yml
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,16 @@ jobs:
DOTNET_CLI_TELEMETRY_OPTOUT: true
steps:
- uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1
with:
submodules: recursive

# The rules come from the engine submodule. Without it, restore fails with a puzzling missing-project error.
- name: Engine submodule
run: |
if [ ! -f external/puzzle-boy-engine/src/PuzzleBoy.Rules/PuzzleBoy.Rules.csproj ]; then
echo "::error::external/puzzle-boy-engine is empty. Check out with submodules, or run: git submodule update --init"
exit 1
fi

- uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0
with:
Expand Down
3 changes: 3 additions & 0 deletions .gitmodules
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
[submodule "external/puzzle-boy-engine"]
path = external/puzzle-boy-engine
url = https://github.com/hazeliscoding/puzzle-boy-engine.git
13 changes: 7 additions & 6 deletions AGENTS.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
# AGENTS.md

These are the working rules for agents in this repo. Puzzle Boy is a standalone, cross-platform rebuild of the Puzzle Boy minigame from *Shin Megami Tensei III Nocturne HD Remaster*, licensed Apache-2.0.
These are the working rules for agents in this repo. Puzzle Boy is a faithful, cross-platform preservation port of the Puzzle Boy minigame from *Shin Megami Tensei III Nocturne HD Remaster*, licensed Apache-2.0.

## Sources of truth

Expand All @@ -13,6 +13,7 @@ These are the working rules for agents in this repo. Puzzle Boy is a standalone,
- **No decompiled code in the source.** Turn what the decompiler shows into a test on a handmade stage, then write the code from the test. Don't paste or transliterate pseudocode.
- **No circumvention.** `GameAssembly.dll` is protected by Denuvo Anti-Tamper. Analyze only its unprotected `.text` section, statically. Don't dump the running game's memory, de-obfuscate protected code or patch the game. If a function leads into protected code, stop and answer the question by playing the real game.
- **No secrets or private paths** in committed files.
- **The original's scope only.** The game plays the original's 20 stages, in its order. Bonus stages, the switch key, stage skipping and anything else the original lacks belong to Puzzle Boy Community Edition.

## Reverse engineering

Expand All @@ -24,18 +25,18 @@ These are the working rules for agents in this repo. Puzzle Boy is a standalone,

## Commands

- `git submodule update --init` fetches the engine from GitHub into `external/puzzle-boy-engine`. To work against unpushed engine commits, point the submodule at a local clone: `git config submodule.external/puzzle-boy-engine.url <path to puzzle-boy-engine>`, then `git -c protocol.file.allow=always submodule update --init`.
- `dotnet build PuzzleBoy.slnx` builds everything. Warnings are errors.
- `dotnet test --solution PuzzleBoy.slnx` runs the tests. They use handmade stages only and never need the game installed.
- `dotnet format PuzzleBoy.slnx --verify-no-changes` checks the style CI will enforce.
- `dotnet run --project src/PuzzleBoy` starts the game, finding the install through Steam. `dotnet run --project src/PuzzleBoy -- <game folder>` points it at a copy elsewhere. Arrow keys or WASD move (hold to keep walking), Q and E turn the view (L1/R1), V switches to overhead (○), Tab scrolls (△), C switches characters on multi-character stages, F opens the menu with undo, restart, help and quit (□), Enter or Space confirms, Backspace cancels, PageUp/PageDown skip stages, Escape quits. The game runs at the original's 30 ticks a second.
- `dotnet run --project src/PuzzleBoy` starts the game, finding the install through Steam. `dotnet run --project src/PuzzleBoy -- <game folder>` points it at a copy elsewhere. Arrow keys or WASD move (hold to keep walking), Q and E turn the view (L1/R1), V switches to overhead (○), Tab scrolls (△), F opens the menu with undo, restart, help and quit (□), Enter or Space confirms, Backspace cancels, Escape quits. The game runs at the original's 30 ticks a second.
- `scripts/check-no-game-data.sh` fails if tracked files hold Atlus data or decompiler output. `scripts/check-no-game-data.test.sh` is its positive control: it plants each kind in a scratch repo and expects a failure. When you add a new kind, add both a check and a planted case.

## Code layout

- `src/PuzzleBoy.Rules`: stage parsing (`Stage`, `Cell`), the rules (`Board`) and the original's play order (`PlayOrder`). No MonoGame and no file I/O, so the tests can drive it with plain bytes.
- Rules tests draw handmade stages as text with `tests/PuzzleBoy.Tests/Ascii.cs`; its summary has the legend. A rule change starts with a drawing of the case.
- `src/PuzzleBoy`: the MonoGame (DesktopGL) game. `GameInstall` finds the player's Steam install, or takes the game folder as the first argument, and reads bundles with AssetsTools.NET. It has no content pipeline; every asset is read at runtime.
- `tests/PuzzleBoy.Tests`: xunit.v3 on Microsoft Testing Platform, covering both projects. Test names read as sentences.
- `external/puzzle-boy-engine`: the shared engine, a pinned git submodule. `PuzzleBoy.Rules` has stage parsing (`Stage`, `Cell`) and the rules (`Board`), with no MonoGame and no file I/O. `PuzzleBoy.Nocturne` finds the install (`GameInstall`) and decodes its bundles. `PuzzleBoy.Rendering` draws the board and Jack (`BoardView`, `CharacterView`, `CharacterModel`), runs the camera and move timing (`ViewCamera`, `MoveAnimation`) and plays `Sounds`. Don't edit them here: a change and its test go into the engine repo first, then this repo bumps the pin with `build: bump engine to <short-sha>`. Community Edition draws its Classic theme with the same code, so a change there changes both games.
- `src/PuzzleBoy`: the MonoGame (DesktopGL) game: the tick loop (`PuzzleBoyGame`), `GameAssets`, the HUD, dialogue, menu and `TextRenderer`. `OriginalStageOrder` lists the original's 20 stage files in order. `Program` finds the player's install through the engine's `GameInstall`, or takes the game folder as the first argument. It has no content pipeline; every asset is read at runtime.
- `tests/PuzzleBoy.Tests`: xunit.v3 on Microsoft Testing Platform, covering the game. The rules, asset-reading and rendering tests live in the engine. Tests that need a board draw it as text with `Ascii.cs`; its summary has the legend. Test names read as sentences.

## Working style

Expand Down
6 changes: 5 additions & 1 deletion PuzzleBoy.slnx
Original file line number Diff line number Diff line change
@@ -1,6 +1,10 @@
<Solution>
<Folder Name="/external/">
<Project Path="external/puzzle-boy-engine/src/PuzzleBoy.Nocturne/PuzzleBoy.Nocturne.csproj" />
<Project Path="external/puzzle-boy-engine/src/PuzzleBoy.Rendering/PuzzleBoy.Rendering.csproj" />
<Project Path="external/puzzle-boy-engine/src/PuzzleBoy.Rules/PuzzleBoy.Rules.csproj" />
</Folder>
<Folder Name="/src/">
<Project Path="src/PuzzleBoy.Rules/PuzzleBoy.Rules.csproj" />
<Project Path="src/PuzzleBoy/PuzzleBoy.csproj" />
</Folder>
<Folder Name="/tests/">
Expand Down
11 changes: 7 additions & 4 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,7 @@
</picture>
</h1>

**The Puzzle Boy minigame from *Shin Megami Tensei III: Nocturne*, as a standalone game.**
**A faithful preservation port of the Puzzle Boy minigame from *Shin Megami Tensei III Nocturne HD Remaster*. It reads your own copy of the game and plays the original 20 stages.**

<p align="center">
<img src="https://github.com/user-attachments/assets/fb27b01d-3f4a-418e-ab2f-b81c402ce16c" alt="Jack-o'-Lantern turns the view, pushes blocks and clears stage 2" width="800">
Expand All @@ -14,7 +14,9 @@

In Nocturne, Puzzle Boy sits deep inside a long RPG. You guide Jack-o'-Lantern through a maze by pushing blocks, turning swivel blocks and filling holes, while the Manikin Kid taunts you. It is a 3D take on Atlus's Game Boy puzzler of the same name, released in the West as Kwirk.

This project rebuilds the minigame so it runs on its own on Windows, macOS and Linux. It reads the stages, text and sounds from your own copy of *Shin Megami Tensei III Nocturne HD Remaster*.
This project rebuilds the minigame so it runs on its own on Windows, macOS and Linux, as a record of how the original plays. It reads the stages, text and sounds from your own copy of *Shin Megami Tensei III Nocturne HD Remaster*.

> **Want more than the original 20?** [Puzzle Boy Community Edition](https://github.com/hazeliscoding/puzzle-boy-community) is the Nocturne minigame expanded: new stages, a level editor, level packs, and the bonus stages and switch key that v0.2.0 had. Its Classic theme comes from your own copy of Nocturne, and without one it plays out of the box with its bundled Default theme. It has no release yet.

> **Status:** early development. The original's rules are decoded and implemented, and all 20 stages can be played from your install with the original's board look, camera, timing, sound, HUD, dialogue, menu and an animated Jack-o'-Lantern. Solutions recorded in the original clear every stage in the port. See [ROADMAP.md](ROADMAP.md).

Expand All @@ -27,7 +29,7 @@ This repository contains no Atlus code or data: no stages, text, audio, textures
1. Download the archive for your system from [Releases](https://github.com/hazeliscoding/puzzle-boy/releases) and unpack it.
2. Run `PuzzleBoy` (`PuzzleBoy.exe` on Windows). It looks for the game beside itself, then in your Steam libraries. If no window opens, it didn't find the game: run it from a terminal with the folder that holds `smt3hd.exe`, for example `PuzzleBoy "D:\Games\smt3hd"`.

Arrow keys or WASD move, Q and E turn the view, V switches to overhead, Tab scrolls, C switches characters on bonus stages with several, F opens the menu (undo, restart, help, quit), Enter or Space confirms, Backspace cancels, PageUp and PageDown skip stages, and Escape quits. Bonus stages, the stage files the original ships but never plays, follow stage 20.
Arrow keys or WASD move, Q and E turn the view, V switches to overhead, Tab scrolls, F opens the menu (undo, restart, help, quit), Enter or Space confirms, Backspace cancels, and Escape quits. After stage 20 the board stays cleared. v0.2.0 also played 23 bonus stages after stage 20; they now belong to Community Edition.

The builds aren't signed, so Windows SmartScreen and macOS Gatekeeper may warn before the first start. On macOS, `xattr -dr com.apple.quarantine` on the unpacked folder lets it run. Nocturne HD has no Mac version, so a Mac needs a copy of the game folder from a PC. Nobody has played the macOS builds yet, so reports are welcome.

Expand All @@ -36,7 +38,8 @@ The builds aren't signed, so Windows SmartScreen and macOS Gatekeeper may warn b
- The 50 stage files in the game's `pazzleboy` asset bundle are small binary grids. Their format is decoded and recorded in the roadmap.
- The rules come from static analysis of the game's code with [REA](https://rea.tools) and Ghidra. The analysis reads only the game's unprotected code and does not bypass its anti-tamper protection.
- Each rule becomes a test on a handmade stage, and the game is written from those tests, never from decompiler output.
- [The docs](docs/README.md) walk through all of it, a few minutes per topic: the journey, the architecture, the rules, the timing, reading the game's files, the rendering, the bonus stages and the checks.
- The rules live in [puzzle-boy-engine](https://github.com/hazeliscoding/puzzle-boy-engine), which Community Edition shares. This repo pins it as a git submodule, so clone with `--recurse-submodules`.
- [The docs](docs/README.md) walk through all of it, a few minutes per topic: the journey, the architecture, the rules, the timing, reading the game's files, the rendering, the bonus stages (now in Community Edition) and the checks.

## License

Expand Down
Loading
Loading