Commit graph

340 commits

Author SHA1 Message Date
120b0aa2a4 Three things, sorry. SDL composite texture bugfix, sprite offset position, some Grid render efficiencies 2026-03-03 23:17:02 -05:00
456e5e676e Version bump: 0.2.7-prerelease-7drl2026 (d496959) -> 0.2.8-7DRL-2026 2026-02-28 11:55:14 -05:00
d496959f8b Windows fix: path doesn't require mode 2026-02-28 11:53:16 -05:00
a52568cc8d entity animation version demo 2026-02-27 22:12:17 -05:00
29fe135161 animation loop parameter 2026-02-27 22:11:29 -05:00
550201d365 CLAUDE guidance 2026-02-27 22:11:10 -05:00
e2d3e56968 Cross-platform persistent save directory (IDBFS on WASM, filesystem on desktop)
Game code uses standard Python file I/O to mcrfpy.save_dir with no platform
branching. On WASM, builtins.open() is monkeypatched so writes to /save/
auto-sync IDBFS on close, making persistence transparent.

API: mcrfpy.save_dir (str), mcrfpy._sync_storage() (auto-called on WASM)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-25 20:42:44 -05:00
453ea4a7eb Version bump: 0.2.6-prerelease-7drl2026 (4404d10) -> 0.2.7-prerelease-7drl2026 2026-02-21 07:58:10 -05:00
4404d1082a Update roadmap for 7DRL 2026 and post-jam 1.0 planning
Rewrite ROADMAP.md to reflect current project state:
- Summarize 0.2 series shipped features (3D/voxel, procgen, Tiled/LDtk,
  WASM, animation callbacks, multi-layer grids, doc macros)
- 7DRL 2026 dates (Feb 28 - Mar 8) and remaining prep
- Post-jam priorities: API freeze process, pain point fixes,
  roguelikedev tutorial series, pip/virtualenv integration
- Engine eras model (McRogueFace -> McVectorFace -> McVoxelFace)
- Future directions: McRogueFace Lite (MicroPython/PicoCalc),
  standard library widgets, package management
- Open issue groupings (30 issues across 8 areas)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 23:18:12 -05:00
9176dca055 Add mcrf-init.sh: game project scaffolding without engine recompilation
New workflow for game developers: run mcrf-init to create a project
directory with symlinks to a pre-built engine, then just write Python
scripts and assets. Games package for distribution (Linux/Windows/WASM)
without ever rebuilding the engine.

mcrf-init.sh creates:
- build/ with symlinked binary and libs, game content in assets/ + scripts/
- build-windows/ (if engine has a Windows build)
- Makefile with run, wasm, dist-linux, dist-windows, dist-wasm targets
- Starter game.py, .gitignore, pyrightconfig.json, VERSION file

CMakeLists.txt: WASM preload paths (assets, scripts) are now
configurable via MCRF_ASSETS_DIR / MCRF_SCRIPTS_DIR cache variables,
so game project Makefiles can point WASM builds at their own content
without modifying the engine.

Also adds pyrightconfig.json for the engine repo itself (IDE support
via stubs/).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 23:17:59 -05:00
732897426a Audio fixes: gain() DSP effect, sfxr phase wrap, SDL2 backend compat
- SoundBuffer.gain(factor): new DSP method for amplitude scaling before
  mixing (0.5 = half volume, 2.0 = double, clamped to int16 range)
- Fix sfxr square/saw waveform artifacts: phase now wraps at period
  boundary instead of growing unbounded; noise buffer refreshes per period
- Fix PySound construction from SoundBuffer on SDL2 backend: use
  loadFromSamples() directly instead of copy-assign (deleted on SDL2)
- Add Image::create(w, h, pixels) overload to HeadlessTypes and
  SDL2Types for pixel data initialization
- Waveform test suite (62 lines)

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 23:17:41 -05:00
80e14163f9 Shade sprite module: faction generation, asset scanning, TextureCache
Extends the shade_sprite module (for merchant-shade.itch.io character
sprite sheets) with procedural faction generation and asset management:

- FactionGenerator: seed-based faction recipes with Biome, Element,
  Aesthetic, and RoleType enums for thematic variety
- AssetLibrary: filesystem scanner that discovers and categorizes
  layer PNGs by type (skins, clothes, hair, etc.)
- TextureCache: avoids redundant disk I/O when building many variants
- CharacterAssembler: HSL shift documentation, method improvements
- Demo expanded to 6 interactive scenes (animation viewer, HSL recolor,
  character gallery, faction generator, layer compositing, equipment)
- EVALUATION.md: 7DRL readiness assessment of the full module
- 329-line faction generation test suite

Assets themselves are not included -- sprite sheets are external
dependencies, some under commercial license.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-20 23:17:24 -05:00
9718153709 Fix callback/timer GC: prevent premature destruction of Python callbacks
closes #251

Two related bugs where Python garbage collection destroyed callbacks
that were still needed by live C++ objects:

1. **Drawable callbacks (all 8 types)**: tp_dealloc unconditionally called
   click_unregister() etc., destroying callbacks even when the C++ object
   was still alive in a parent's children vector. Fixed by guarding with
   shared_ptr::use_count() <= 1 — only unregister when the Python wrapper
   is the last owner.

2. **Timer GC prevention**: Active timers now hold a Py_INCREF'd reference
   to their Python wrapper (Timer::py_wrapper), preventing GC while the
   timer is registered in the engine. Released on stop(), one-shot fire,
   or destruction. mcrfpy.Timer("name", cb, 100) now works without storing
   the return value.

Also includes audio synth demo UI fixes: button click handling (don't set
on_click on Caption children), single-column slider layout, improved
Animalese contrast.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 20:53:50 -05:00
97dbec9106 Add SoundBuffer type: procedural audio, sfxr synthesis, DSP effects
New SoundBuffer Python type enables procedural audio generation:
- Tone synthesis (sine, square, saw, triangle, noise) with ADSR envelopes
- sfxr retro sound effect engine (7 presets, 24 params, mutation, seeding)
- DSP effects chain: pitch_shift, low/high pass, echo, reverb,
  distortion, bit_crush, normalize, reverse, slice
- Composition: concat (with crossfade overlap) and mix
- Sound() now accepts SoundBuffer or filename string
- Sound gains pitch property and play_varied() method
- Platform stubs for HeadlessTypes and SDL2Types (loadFromSamples, pitch)
- Interactive demo: sfxr clone UI + Animalese speech synthesizer
- 62 unit tests across 6 test files (all passing)

Refs #251

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-19 18:58:11 -05:00
bb72040396 Migrate static PyTypeObject to inline, delete PyTypeCache workarounds
All 27 PyTypeObject declarations in namespace mcrfpydef headers changed
from `static` to `inline` (C++17), ensuring a single global instance
across translation units. This fixes the root cause of stale-type-pointer
segfaults where only the McRFPy_API.cpp copy was PyType_Ready'd.

Replaced ~20 PyTypeCache call sites and 2 PyRAII::PyTypeRef lookups with
direct &mcrfpydef::Type references. Deleted PyTypeCache.h/.cpp,
PyObjectUtils.h, and PyRAII.h (all were workarounds for the static bug).

228/228 tests pass.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-16 20:58:09 -05:00
6fdf7279ce Shade (merchant-shade.itch.io) entity animation tests 2026-02-16 20:19:39 -05:00
2681cbd957 Crypt of Sokoban remaster continued 2026-02-16 18:39:38 -05:00
686e4fc1b2 Replace forward BFS solver with reverse-pull puzzle generation
The BFS solver couldn't account for obstacles blocking push paths -
knowing the button is reachable doesn't mean the player can get to
the correct side of the boulder. Reverse-pull guarantees solvability
by construction: start with boulder on button, simulate valid
un-pushes to move it away. Each un-push verifies both the new boulder
cell and the player's required push position are walkable.

Also fixes chest clumping: level 2 previously crammed 3 treasures +
boulder + button into a single room. Redesigned all level plans to
spread treasures across rooms (max 1 per room). Updated lv_planner
for procedural levels 9+ with the same constraint.

Level plans no longer specify "boulder" - it's auto-generated from
the button position with min_pulls scaling by depth (2-8).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 08:36:43 -05:00
4c809bdd0f Fix Sokoban puzzle: prevent treasure/button overlap and model obstacles in solver
Three bugs that could produce unsolvable puzzles:

1. Feature placement fallback used leaf_center without duplicate checking,
   allowing treasures to spawn on the same cell as buttons in dense rooms
   (level 2 puts 8 features in one room). Fixed with exhaustive cell scan
   fallback.

2. Solvability checker ignored treasure entities entirely. Boulders cannot
   be pushed through treasures (TreasureEntity.bump returns False for
   non-player entities), so the solver now models them as boulder-blocking
   obstacles while allowing player movement through them.

3. Added explicit button-blocked-by-obstacle check before running the
   full BFS solver, catching the most common failure mode early.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-15 02:36:46 -05:00
99f439930d Crypt of Sokoban remaster: BSP, FOV, enemy AI, solvability checker
Replaces jam-quality code with production engine features (addresses #248):

- cos_level.py: Replace custom BinaryRoomNode/RoomGraph with mcrfpy.BSP
  for room generation, using adjacency graph for corridor placement
- cos_solver.py: New Sokoban BFS solvability checker; levels retry up
  to 10 times if unsolvable
- game.py: Add ColorLayer fog of war with room-reveal mechanic
  (visible/discovered/unknown states), compute_fov per player move
- cos_entities.py: Enemy AI state machine (idle/aggressive/fleeing)
  with A* pathfinding, fix duplicate direction bug on line 428/444

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-14 20:34:14 -05:00
7855a7ad80 Version bump: 0.2.5-prerelease-7drl2026 (50eba33) -> 0.2.6-prerelease-7drl2026 2026-02-14 11:13:57 -05:00
50eba3314b more gitignore 2026-02-14 11:04:28 -05:00
945cce3f88 crypt of sokoban layer API change updates 2026-02-14 11:04:19 -05:00
726a9cf09d Mobile-"ish" emscripten support
Full screen "wasm-game" for viewport compatibility between desktop and
web interfaces. Viewport modes ("fit", "center", and "stretch") should
now work the same way under WASM/SDL and SFML. This should also enable
android or web-for-mobile aspect ratios to be supported more easily.
2026-02-09 08:40:34 -05:00
24611c339c gitignore images 2026-02-09 08:16:45 -05:00
52fdfd0347 Test suite modernization 2026-02-09 08:15:18 -05:00
0969f7c2f6 Implement SDL2_mixer audio for WASM builds, closes #247
Replace no-op audio stubs in SDL2Types.h with real SDL2_mixer-backed
implementations of SoundBuffer, Sound, and Music. This enables audio
playback in the browser with zero changes to Python bindings.

- Add -sUSE_SDL_MIXER=2 to Emscripten compile/link flags (CMakeLists.txt)
- Initialize Mix_OpenAudio in SDL2Renderer::init(), Mix_CloseAudio in shutdown()
- SoundBuffer: Mix_LoadWAV/Mix_LoadWAV_RW with duration computation
- Sound: channel-based playback with Mix_ChannelFinished tracking
- Music: global channel streaming via Mix_LoadMUS/Mix_PlayMusic
- Volume conversion: SFML 0-100 scale to SDL_mixer 0-128 scale

Known limitations on web: Music.duration and Music.position getters
return 0 (SDL_mixer 2.0.2 lacks Mix_MusicDuration/Mix_GetMusicPosition).

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-08 22:16:21 -05:00
ef05152ea0 Implement Entity3D.animate(), closes #242
Replaced the NotImplementedError stub with a full animation
implementation. Entity3D now supports animating: x, y, z,
world_x, world_y, world_z, rotation, rot_y, scale, scale_x,
scale_y, scale_z, sprite_index, visible.

Added Entity3D as a third target type in the Animation system
(alongside UIDrawable and UIEntity), with startEntity3D(),
applyValue(Entity3D*), and proper callback support.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 20:16:02 -05:00
9e2444da69 Add pop/find/extend to EntityCollection3D, closes #243
EntityCollection3D now has API parity with UIEntityCollection:
- pop(index=-1): Remove and return entity at index
- find(name): Search by entity name, return Entity3D or None
- extend(iterable): Append multiple Entity3D objects

Also adds `name` property to Entity3D for use with find().

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 20:15:55 -05:00
f766e9efa2 Add y_plane parameter to screen_to_world(), closes #245
screen_to_world() previously only intersected the Y=0 plane.
Now accepts an optional y_plane parameter (default 0.0) for
intersecting arbitrary horizontal planes.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 20:15:48 -05:00
d195c0e390 Add warning when RenderTexture creation fails, closes #227
Previously enableRenderTexture() silently failed. Now emits a
stderr warning with the requested dimensions, consistent with
the engine's logging pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 20:15:43 -05:00
2062e4e4ad Fix Entity3D.viewport returning None, closes #244
The root cause was PyViewport3DType being declared `static` in
Viewport3D.h, creating per-translation-unit copies. Entity3D.cpp's
copy was never passed through PyType_Ready, causing segfaults when
tp_alloc was called.

Changed `static` to `inline` (matching PyEntity3DType and
PyModel3DType patterns), and implemented get_viewport using the
standard type->tp_alloc pattern.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-02-07 20:15:38 -05:00
b9a48a85b0 Version bump: 0.2.4-prerelease-7drl2026 (3ce7de6) -> 0.2.5-prerelease-7drl2026 2026-02-07 11:55:29 -05:00
3ce7de6134 Windows/WASM platform fixes 2026-02-07 11:54:01 -05:00
de7778b147 LDtk import support 2026-02-07 11:34:38 -05:00
322beeaf78 add __ne__ support to enum types for input 2026-02-06 21:43:52 -05:00
b093e087e1 Tiled XML/JSON import support 2026-02-06 21:43:03 -05:00
71cd2b9b41 3D / voxel unit tests 2026-02-06 16:15:07 -05:00
e12e80e511 add run banner to canvas in playground 2026-02-05 23:03:02 -05:00
de5616f3a4 voxel, animation, and pathfinding combined demo 2026-02-05 22:57:08 -05:00
992ea781cb Voxel functionality extension 2026-02-05 12:52:18 -05:00
3e6b6a5847 voxel example 2026-02-05 10:49:31 -05:00
7ebca63db3 emscripten build fixes 2026-02-05 00:29:40 -05:00
f2ccdff499 Frustum culling 2026-02-04 23:45:43 -05:00
7e8efe82ec 3D target demo 2026-02-04 23:41:37 -05:00
cc027a2517 rigging and animation 2026-02-04 23:19:03 -05:00
b85f225789 billboards 2026-02-04 20:47:51 -05:00
544c44ca31 glTF model loading 2026-02-04 19:35:48 -05:00
8636e766f8 fix: don't use SFML GL context management in SDL builds 2026-02-04 17:48:34 -05:00
f4c9db8436 3D entities 2026-02-04 17:45:12 -05:00