- GDScript 66.8%
- Python 32%
- GDShader 1.2%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
|
All checks were successful
Deploy Web Build / Export Web & publish (push) Successful in 2m56s
EXP per kill is species exp * level / 4.5 (was / 7), and every living Husk on the bench takes half, levelling and molting where it sits. Sump Road and Boneward Mire binders drop a level; Scavenger Pell's lone HOLLOWCROW, which no CINDREL or SLOUGHLING could beat, becomes a WIRETICK and STITCHKIN. Wild HOLLOWCROW tops out at L4. SLOUGHLING gets sturdier base stats and FESTER from the start so it is not helpless against the road's RUST and ROT. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01FbWB5fUsBuoRFcMotPvuZj |
||
| .forgejo/workflows | ||
| assets | ||
| data/maps | ||
| src | ||
| tests | ||
| tools | ||
| .editorconfig | ||
| .gitattributes | ||
| .gitignore | ||
| export_presets.cfg | ||
| icon.svg | ||
| icon.svg.import | ||
| justfile | ||
| project.godot | ||
| README.md | ||
IRONGRAVE
A grim, pixel-art monster-binding RPG built in Godot 4.7. It should feel like a bad dream. One in ten. Every year.
The Tithe took your sister up the Spire to feed the Furnace. You bind what the Spire's light left behind, and you climb after her. Nobody comes back from the Furnace. You are going anyway.
Running
Open the folder in Godot 4.7 (GL Compatibility renderer) and press Play, or:
godot --path .
The game renders at 480x320 and scales by integers (960x640 windowed).
Web build
export_presets.cfg has a single-threaded Web preset (no special server
headers needed; music composes on the main thread when there are no threads):
godot --headless --path . --export-release "Web" build/web/index.html
.forgejo/workflows/deploy.yml does the same on every branch push: it runs
tests/Smoke.tscn, exports, and copies the build to
/srv/deploy/irongrave/<branch>/, a directory the Forgejo runner must mount into
the job container (see the comment at the top of the workflow).
| Key | Action |
|---|---|
| Arrows / WASD | Move, menu navigation |
| Z / Space / Enter | Accept, talk, advance text |
| X / Shift | Cancel |
| Esc / Tab | Pause menu (Husks, Scrap, Save) |
| Gamepad | D-pad or left stick to move, A accept, B cancel, Start or Y for the menu |
Win condition
Climb from Cinderhollow through the Sump Road, Rustmarket, the Boneward Mire and the Pale Chapel (Warden Scald), up the Spire Road (Warden Vesper) to the Furnace. Defeat the Reeve, then defeat CINDERTHRONE, the Furnace's heart. The light goes out. That is the ending. There is not a better one.
Systems
- 24 unique Husks across 7 types: RUST, FLESH, EMBER, ROT, VOID, BONE, STATIC.
- 45 moves, 4 statuses (BLEED, BURN, SEIZE, DREAD), stat stages, STAB, crits.
- Binding (catching) with Shackles. Trainer Husks cannot be bound.
- Levelling, move learning, Molting (evolution) for the three starters, FERROHOUND and DIRGELING.
- A broken Husk has a 10% chance of not getting up again. Permanently.
- Losing every Husk plays an escape scene (
src/Escape.tscn), then sends you back to the last Stitcher with half your scrap. - Save at a Stitcher or from the pause menu. Saved to
user://irongrave.save.
Project layout
assets/ generated pixel art (run tools/*.py to regenerate; never hand-edit)
src/autoload/ DB (data), Game (state), Sfx (procedural chip sounds), Music (generative chiptune), Husk
data/maps/ one JSON file per map: ASCII rows, warps, NPCs, trainers, encounters
src/world/ Maps (loads data/maps, tile legend, map checks), Overworld, Story events
src/dev/ MapEditor (dev tool, not reachable from the game)
src/battle/ Battle engine
src/ui/ Dialogue box, party/item screens, pause menu
tests/ Smoke.tscn (data + logic), Play.tscn (scripted playthrough), MapEditor.tscn
tools/ Python (PIL + numpy) generators: palette, drawing kit, Husks, tiles, figures, portraits, font, logo
Editing maps
just editor
That runs godot --path . res://src/dev/MapEditor.tscn.
The map editor paints tiles, places and edits warps and NPCs, resizes maps, creates new ones,
and saves them back to data/maps/<id>.json.
- Tools. B paint, G flood fill, R rectangle, V select. Right-click picks the tile under the cursor.
- View. Wheel zooms. Middle-drag or Space+drag pans.
- Entities. With Select, click a warp or NPC and drag it to move it. Edit its JSON on the right and press Apply. Double-click a warp to open the map it leads to.
- History. Ctrl+Z / Ctrl+Y undo and redo per map. Ctrl+S saves the current map, Ctrl+Shift+S saves all.
- Problems. The list on the right runs the same checks as
tests/Smoke.tscn: ragged rows, bad warps, unknown music, and exits or NPCs a player can't reach. Unreachable floor is tinted red. Click a problem to jump to it. A structurally broken map won't save; other problems only warn. - Playtest. F5 runs the edited map in the real game from the last clicked cell, with a level 20 Husk. F5 again returns to the editor with unsaved edits and undo history intact.
The map files are plain JSON with one row, warp or NPC per line, so hand edits and diffs work too.
Run tests/Smoke.tscn after changing maps. An exported build must include data/* as a non-resource file.
Regenerate art (every asset is procedural; tools/palette.py holds the twelve colour ramps and
tools/art.py the shading kit they all share):
python3 tools/gen_font.py assets/font
python3 tools/gen_monsters.py assets/monsters
python3 tools/gen_world.py assets
python3 tools/gen_portraits.py assets/ui/portraits
godot --headless --import --path . # after adding new asset files
Sizes: 32px tiles, 32x40 overworld figures (8 frames: down/up/left/right, two steps each), 120px Husk fronts, 160px backs, 32px icons, 80px portraits, 480x224 battle backdrop, 36px 9-slice UI panel.
Run tests headless:
godot --headless --path . res://tests/Smoke.tscn
godot --headless --path . res://tests/Play.tscn
godot --headless --path . res://tests/MapEditor.tscn