Commit graph

25 commits

Author SHA1 Message Date
98489a96fd Fix verify-pass code bugs #317/#318/#319
Three small bugs surfaced by the #314 docstring-accuracy verify pass:

#317 automation.scroll() dropped the x of its position argument: scroll()
resolved (x, y) but called injectMouseEvent(MouseWheelScrolled, clicks, y),
passing the scroll amount as x. injectMouseEvent now takes the scroll delta as
its own parameter and scroll() forwards the real x/y.

#318 GridView.texture always returned None (a TODO stub). It now returns a
Texture wrapper sharing the underlying shared_ptr<PyTexture>, mirroring
Grid.texture. (mcrfpy.Grid and mcrfpy.GridView are the same type post-#252, so
this fixes both names.)

#319 Entity.visible_entities(radius=None) raised TypeError: radius was parsed
with the 'i' format code, which rejects None. It now parses radius as an object
and treats None / omitted / -1 as "use the grid's default fov_radius"; a
non-int, non-None radius raises a clear TypeError.

- regression tests for each under tests/regression/
- api_surface snapshot re-baselined (visible_entities signature; texture
  property now Texture | None) and docs/stubs regenerated; frozen docstring
  gate still 100%

closes #317
closes #318
closes #319

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_01KnywUddaFRhkxo5kijxJnv
2026-06-21 10:12:41 -04:00
eafe65683f F15: correct docstring accuracy from adversarial verify pass (#314)
Follow-up to the macro conversion: an adversarial verify pass (one agent per
file vs. the C++ implementation + stubs) found 62 content issues; the real
ones are fixed here.

Callbacks (centralized):
- on_click: receives (pos, MouseButton, InputState), not str (8 files).
- on_enter/on_exit/on_move (UIBase.h): hover passes only (pos) -- removed the
  fictional button/action args.
- bounds/global_bounds (UIBase.h): mark (tuple, read-only).

Signatures / types:
- Grid.find_path: document heuristic + weight; get_dijkstra_map: document roots;
  compute_fov: FOV | int = FOV.BASIC (not the C constant FOV_BASIC) + Returns;
  at/is_in_fov: document (pos) and (x, y) call forms.
- get_metrics: document all 16 returned dict keys (was 8); bresenham: drop the
  bogus '*' keyword-only separator.
- Nullable defaults typed correctly: BSP seed/size, ColorLayer draw_fov/
  apply_perspective Color|None, Entity.visible_entities radius int=-1 (None is
  rejected by the 'i' parser -> see #319).
- Type-token fixes: GridView.center -> Vector; GridView.texture -> (None,
  read-only) (unimplemented, #318); GridPoint.grid_pos -> (tuple, read-only);
  EntityCollection.find -> Entity | list[Entity] | None; extend RuntimeError;
  UniformCollection.values -> list[float | tuple | None].
- automation: onScreen (x, y) form documented; scroll notes x is ignored (#317).

Also: correct stale AStarPath/DijkstraMap signatures in docs/api-audit-2026-04.md
(the bindings were right, the audit table was outdated). Rebaseline the API
snapshot golden and regenerate docs/stubs.

Code-level bugs surfaced by the pass are filed as #317, #318, #319.

Refs #314, #317, #318, #319

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 06:43:47 -04:00
5725a4f035 F15: convert frozen binding docstrings to MCRF_* macros (#314)
Convert 289 raw PyMethodDef/PyGetSetDef docstring slots to MCRF_METHOD /
MCRF_PROPERTY across the 20 frozen (non-3D) binding files, bringing the
frozen surface to 100% macro compliance (check_frozen_docstrings.sh PASS).
Done via a one-agent-per-file workflow gated by validate_file_docstrings.sh
and per-wave build/doc-rebuild checks.

- Adds #include "McRFPy_Doc.h" where missing; fills the lone genuine doc
  gap (UIGrid.at, which was MISSING a doc field in two arrays).
- McRFPy_Doc.h: comment documenting the MCRF_METHOD_DOC comma rule (the
  trap that broke the GridLayers conversion mid-run).
- Rebaseline api_surface golden: property types now resolve to real types
  instead of "Any" (e.g. grid_pos: Vector, on_cell_click: Callable | None),
  and 11 properties correctly flip rw->ro now that their docstrings carry
  "read-only" (collections, grid_size, hovered_cell, texture, view — all
  verified against NULL setter slots).
- Regenerate docs/stubs/man page from the new docstrings.

Module-level functions use MCRF_METHOD(<name>, ...) (expands identically to
the intended MCRF_FUNCTION; the audit's compliance set is METHOD/PROPERTY).
Experimental 3D/Voxel bindings (src/3d/) remain exempt from the freeze.

Pre-existing failures unrelated to this change: test_animation_*,
test_constructor_comprehensive (reference the removed mcrfpy.Animation and
old constructor arity).

Refs #314

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
2026-06-21 01:20:55 -04:00
2d2c333cd7 Refactor UIEntity::grid to shared_ptr<GridData>; add entity.texture; closes #313
UIEntity now depends on the grid DATA layer only:
- GridData gains cell_width_px/cell_height_px (mirrored from the grid
  texture in UIGrid's 5-arg ctor; texture is write-once) so entity
  tile<->pixel math no longer reaches into rendering (getTexture()).
- GridData gains markDirty()/markCompositeDirty(): set the flag on the
  UIGrid subobject AND notify owning_view, covering both render paths.
  UIGrid disambiguates via 'using UIDrawable::markDirty' so all
  pre-existing UIGrid-receiver calls resolve exactly as before.
- The three Python wrappers that still need the full UIGrid (GridPoint
  from entity.at(), the _GridData fallback in get_grid, find_path's temp
  wrapper) reconstruct it via a single aliasing-downcast helper
  (grid_as_uigrid) that documents the never-independently-allocated
  GridData invariant; init/set_grid simplify (share grid_data directly).
  Removing the casts is deferred to #252.

entity.texture (new, frozen surface +1): thin get/set over the entity's
own UISprite. Entities render with their OWN texture (default_texture
fallback at construction); the grid's texture only determines cell size.
Setter preserves sprite_index; rejects non-Texture (TypeError),
null-data Texture wrappers (ValueError), and deletion.

Adversarial review fixes folded in:
- set_texture/get_texture guard uninitialized Entity wrappers
  (RuntimeError), isinstance errors, and null-data Textures.
- PyUIGridViewType tp_dealloc no longer unconditionally severs
  GridData::owning_view: gated on last-owner (#251 use_count pattern)
  plus owning-view identity. Previously ANY Grid wrapper GC while the
  view lived (e.g. scene.children.append(mcrfpy.Grid(...))) silently
  broke entity.grid -> Grid identity and data-layer dirty notification.

Tests: tests/regression/issue_313_entity_grid_data_test.py (texture
semantics, grid-cell-size invariance, entity.grid identity, #251 gate
survival, GridPoint outliving teardown, review-fix guards, owning_view
survival) + tests/unit/entity_texture_test.py. API snapshot golden
re-baselined: exactly +1 surface line (Entity.texture) + writability
probe flip. Docs/stubs regenerated. Native + Emscripten builds verified.

Known edges recorded in docs/api-audit-2026-04.md: texture read-back is
a fresh wrapper each get (no Texture __eq__); sprite_index not
re-validated against a new atlas. Multi-view markDirty broadcast and
pure-GridData wrappers remain deferred to #252. Addresses #314.

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-06-11 00:51:22 -04:00
98d2b36739 Regenerate docs and stubs after API freeze pass
Picks up the five 1.0 freeze commits (groups A-D + Grid follow-up):
  * mcrfpy.Animation removed from module exports
  * parent= kwarg on Frame/Caption/Sprite/Line/Circle/Arc/Grid
  * grid= kwarg on ColorLayer/TileLayer
  * Constructor positional reorders (Circle, Caption, Layers)
  * __getitem__/__setitem__ on ColorLayer/TileLayer/Grid

PyMethodDef/PyGetSetDef compliance baseline (per tools/audit_pymethoddef.py):
  PyGetSetDef: 190/410 MACRO (46.3%)
  PyMethodDef: 150/345 MACRO (43.5%)
413 raw-string docstring entries remain to migrate to MCRF_METHOD/
MCRF_PROPERTY in a separate sweep.
2026-04-18 13:35:26 -04:00
2086d25581 Phase 5.3: documentation regeneration + introspection-based stub generator
Regenerate HTML/Markdown API reference, man page, and type stubs against
current committed HEAD (post API-freeze pass #304-#308, #252 overhaul, and
Phase 3/4/5.1/5.2 changes).

The previous tools/generate_stubs_v2.py hand-maintained hardcoded strings,
which drifted badly: stubs still contained removed module functions
(setScale, findAll, getMetrics, setDevConsole), lacked new types (GridView,
Behavior, Trigger, DiscreteMap, Viewport3D, Entity3D, Model3D, Billboard,
NoiseSource, WangSet, LdtkProject, HeightMap, DijkstraMap, AStarPath,
ColorLayer, TileLayer, etc.), and missed post-overhaul properties
(tile_width/tile_height, sprite_grid, perspective_map, cell_pos, labels,
turn_order, move_speed, etc.).

Rewrite the generator as a runtime-introspection script mirroring
generate_dynamic_docs.py's approach:
  - classify mcrfpy members (classes, enums, functions, constants, submodules)
  - parse signatures from docstring first line with proper paren-depth tracking
  - translate multi-form signatures (foo(x,y) or foo(pos)) to *args/**kwargs
  - sanitize docstring '...' placeholder params into '**kwargs'
  - emit IntEnum blocks for int-subclass types with uppercase members
  - discover delegated methods via instance probing (Grid/GridView -> _GridData)
  - conservative property type inference (only accept recognized primitives
    and CapitalCase class names in parenthesized hints)

Resulting stubs/mcrfpy.pyi (2069 lines) parses as valid Python.
Markdown/HTML/man-page regeneration is otherwise timestamp-only since the
introspection path was already current -- the stubs were the stale artifact.
2026-04-18 07:33:51 -04:00
f797120d53 Replace UIEntity gridstate with DiscreteMap perspective_map; closes #294
Per-entity FOV memory moves from std::vector<UIGridPointState> (two-bool
visible/discovered pairs) to a 3-state DiscreteMap (0=UNKNOWN, 1=DISCOVERED,
2=VISIBLE), exposed as entity.perspective_map. The invariant
visible-subset-of-discovered becomes structural (single value per cell), and
the map is a live, serializable, first-class object rather than an implicit
internal array.

Changes:
- New DiscreteMap C++ class with shared ownership; PyDiscreteMapObject now
  holds shared_ptr<DiscreteMap>. UIEntity holds the same shared_ptr.
- New mcrfpy.Perspective IntEnum (UNKNOWN/DISCOVERED/VISIBLE), modelled on
  PyInputState.
- entity.perspective_map: lazy-allocated on first access with a grid;
  setter validates size against grid and raises ValueError on mismatch;
  None clears (next access lazy-reallocates fresh).
- updateVisibility() now demotes 2->1 then promotes visible cells to 2.
- entity.at(x, y) returns grid.at(x, y) when VISIBLE, else None.
- Fog-of-war rendering in UIGridView and UIGrid reads the 3-state map.
- Removed: UIEntity::gridstate, ensureGridstate(), entity.gridstate getter,
  UIGridPointState struct + PyUIGridPointStateType.
- Obsolete tests deleted (test_gridpointstate_point,
  issue_265_gridpointstate_dangle); 4 new tests cover lazy allocation,
  identity, serialization round-trip, size validation, and the
  visible-subset-of-discovered invariant.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-04-17 23:04:27 -04:00
e7462e37a3 Remove camelCase module functions (setScale, findAll, getMetrics, setDevConsole), closes #304
Breaking API change: removes 4 camelCase function aliases from the mcrfpy
module. The snake_case equivalents (set_scale, find_all, get_metrics,
set_dev_console) remain and are the canonical API going forward.

- Removed setScale, findAll, getMetrics, setDevConsole from mcrfpyMethods[]
- Updated game scripts to use snake_case names
- Updated test scripts to use snake_case names
- Removed camelCase entries from type stubs

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-10 01:07:22 -04:00
c15d836e79 Remove deprecated sprite_number property from Sprite and Entity, closes #305
sprite_number was a legacy alias for sprite_index. All code should use
sprite_index directly. Removed from getsetters, setProperty/getProperty/
hasProperty in UISprite and UIEntity, animation property handling, and
type stubs.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-04-09 22:18:20 -04: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
5a1948699e Update documentation for API changes #229, #230, #184
CLAUDE.md updates:
- Fix Python version 3.12 -> 3.14
- Update keypressScene -> scene.on_key pattern
- Add API examples for new callback signatures
- Document animation callbacks (target, prop, value)
- Document hover callbacks (position-only)
- Document enum types (Key, MouseButton, InputState)

stubs/mcrfpy.pyi updates:
- Add Key, MouseButton, InputState, Easing enum classes
- Fix Drawable hover callback signatures per #230
- Fix Grid cell callback signatures per #230
- Fix Scene.on_key signature to use enums per #184
- Update Animation class with correct callback signature per #229
- Add deprecation notes to keypressScene, setTimer, delTimer

Regenerated docs:
- API_REFERENCE_DYNAMIC.md
- api_reference_dynamic.html
- mcrfpy.3 man page

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-28 19:20:04 -05:00
4be2502a10 Fix #161: Update Grid, GridPoint, GridPointState stubs to match current API
- Grid: Update constructor (pos, size, grid_size, texture, ...) and add all
  current properties (zoom, center, layers, FOV, cell events, etc.)
- Grid: Add all methods (find_path, compute_fov, add_layer, entities_in_radius, etc.)
- GridPoint: Replace incorrect properties (texture_index, solid, color) with
  actual API (walkable, transparent, entities, grid_pos)
- GridPointState: Replace incorrect properties with actual API (visible, discovered, point)
- Add missing types: ColorLayer, TileLayer, FOV, AStarPath, DijkstraMap,
  HeightMap, NoiseSource, BSP

Closes #161

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-21 21:47:26 -05:00
39a12028a0 using custom libtcod-headless 2.2.2 feature branch: fixes to convolution, gradient method 2026-01-19 14:10:07 -05:00
65b5ecc5c7 Stubs definition update 2026-01-13 20:41:38 -05:00
9eacedc624 Input Enums instead of strings. 2026-01-10 21:31:20 -05:00
75127ac9d1 mcrfpy.Mouse: a new class built for symmetry with mcrfpy.Keyboard. Closes #186 2026-01-06 21:39:01 -05:00
357c2ac7d7 Animation fixes: 0-duration edge case, integer value bug resolution 2026-01-04 00:45:16 -05:00
c025cd7da3 feat: Add Sound/Music classes, keyboard state, version (#66, #160, #164)
Replace module-level audio functions with proper OOP API:
- mcrfpy.Sound: Wraps sf::SoundBuffer + sf::Sound for short effects
- mcrfpy.Music: Wraps sf::Music for streaming long tracks
- Both support: volume, loop, playing, duration, play/pause/stop
- Music adds position property for seeking

Add mcrfpy.keyboard singleton for real-time modifier state:
- shift, ctrl, alt, system properties (bool, read-only)
- Queries sf::Keyboard::isKeyPressed() directly

Add mcrfpy.__version__ = "1.0.0" for version identity

Remove old audio API entirely (no deprecation - unused in codebase):
- createSoundBuffer, loadMusic, playSound
- setMusicVolume, getMusicVolume, setSoundVolume, getSoundVolume

closes #66, closes #160, closes #164

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-29 16:24:27 -05:00
89986323f8 docs: Add missing Drawable callbacks and Scene.on_key to stubs
Add to Drawable base class:
- on_click, on_enter, on_exit, on_move callbacks (#140, #141)
- hovered read-only property (#140)

Add to Scene class:
- children property (#151)
- on_key handler property

Discovered while defining implementation details for #143.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 14:49:17 -05:00
da6f4a3e62 docs: Add Line/Circle/Arc to stubs and fix click→on_click
- Add Line, Circle, Arc class definitions to type stubs
- Update UIElement type alias to include new drawable types
- Rename click kwarg to on_click throughout stubs (matches #126 change)
- Update UICollection docstring to list all drawable types

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 14:36:54 -05:00
c9c7375827 refactor: Rename click kwarg to on_click for API consistency (closes #126)
BREAKING CHANGE: Constructor keyword argument renamed from `click` to
`on_click` for all UIDrawable types (Frame, Caption, Sprite, Grid, Line,
Circle, Arc).

Before: Frame(pos=(0,0), size=(100,100), click=handler)
After:  Frame(pos=(0,0), size=(100,100), on_click=handler)

The property name was already `on_click` - this makes the constructor
kwarg match, completing the callback naming standardization from #139.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 14:31:22 -05:00
58efffd2fd feat: Animation property locking prevents conflicting animations (closes #120)
Add AnimationConflictMode enum with three modes:
- REPLACE (default): Complete existing animation and start new one
- QUEUE: Wait for existing animation to complete before starting
- ERROR: Raise RuntimeError if property is already being animated

Changes:
- AnimationManager now tracks property locks per (target, property) pair
- Animation.start() accepts optional conflict_mode parameter
- Queued animations start automatically when property becomes free
- Updated type stubs with ConflictMode type alias

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2025-12-28 13:21:50 -05:00
d761b53d48 docs: Update grid demo and regenerate API docs
- grid_demo.py: Updated for new layer-based rendering
- Screenshots: Refreshed demo screenshots
- API docs: Regenerated with latest method signatures

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-02 09:21:43 -05:00
4e94291cfb docs: Complete Phase 7 documentation system with parser fixes and man pages
Fixed critical documentation generation bugs and added complete multi-format
output support. All documentation now generates cleanly from MCRF_* macros.

## Parser Fixes (tools/generate_dynamic_docs.py)

Fixed parse_docstring() function:
- Added "Raises:" section support (was missing entirely)
- Fixed function name duplication in headings
  - Was: `createSoundBuffercreateSoundBuffer(...)`
  - Now: `createSoundBuffer(filename: str) -> int`
- Proper section separation between Returns and Raises
- Handles MCRF_* macro format correctly

Changes:
- Rewrote parse_docstring() to parse by section markers
- Fixed markdown generation (lines 514-539)
- Fixed HTML generation (lines 385-413, 446-473)
- Added "raises" field to parsed output dict

## Man Page Generation

New files:
- tools/generate_man_page.sh - Pandoc wrapper for man page generation
- docs/mcrfpy.3 - Unix man page (section 3 for library functions)

Uses pandoc with metadata:
- Section 3 (library functions)
- Git version tag in footer
- Current date in header

## Master Orchestration Script

New file: tools/generate_all_docs.sh

Single command generates all documentation formats:
- HTML API reference (docs/api_reference_dynamic.html)
- Markdown API reference (docs/API_REFERENCE_DYNAMIC.md)
- Unix man page (docs/mcrfpy.3)
- Type stubs (stubs/mcrfpy.pyi via generate_stubs_v2.py)

Includes error checking (set -e) and helpful output messages.

## Documentation Updates (CLAUDE.md)

Updated "Regenerating Documentation" section:
- Documents new ./tools/generate_all_docs.sh master script
- Lists all output files with descriptions
- Notes pandoc as system requirement
- Clarifies generate_stubs_v2.py is preferred (has @overload support)

## Type Stub Decision

Assessed generate_stubs.py vs generate_stubs_v2.py:
- generate_stubs.py has critical bugs (missing commas in method signatures)
- generate_stubs_v2.py produces high-quality manually-maintained stubs
- Decision: Keep v2, use it in master script

## Files Modified

Modified:
- CLAUDE.md (25 lines changed)
- tools/generate_dynamic_docs.py (121 lines changed)
- docs/api_reference_dynamic.html (359 lines changed)

Created:
- tools/generate_all_docs.sh (28 lines)
- tools/generate_man_page.sh (12 lines)
- docs/mcrfpy.3 (1070 lines)
- stubs/mcrfpy.pyi (532 lines)
- stubs/mcrfpy/__init__.pyi (213 lines)
- stubs/mcrfpy/automation.pyi (24 lines)
- stubs/py.typed (0 bytes)

Total: 2159 insertions, 225 deletions

## Testing

Verified:
- Man page viewable with `man docs/mcrfpy.3`
- No function name duplication in docs/API_REFERENCE_DYNAMIC.md
- Raises sections properly separated from Returns
- Master script successfully generates all formats

## Related Issues

Addresses requirements from Phase 7 documentation issues.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 21:20:50 -04:00