Commit graph

69 commits

Author SHA1 Message Date
b85f225789 billboards 2026-02-04 20:47:51 -05:00
544c44ca31 glTF model loading 2026-02-04 19:35:48 -05:00
f4c9db8436 3D entities 2026-02-04 17:45:12 -05:00
63008bdefd pathfinding on heightmap 2026-02-04 16:36:21 -05:00
e277663ba0 3D viewport, milestone 1 2026-02-04 13:33:14 -05:00
d8fec5fea0 DiscreteMap class - mask for operations or uint8 tile data 2026-02-03 20:36:42 -05:00
2fb29a102e Animation and Scene clean up functions. Playground build target 2026-02-01 21:17:29 -05:00
3b27401f29 Remove debugging output 2026-02-01 16:40:23 -05:00
c5cc022aa2 Add SDL2+OpenGL ES 2 renderer backend for Emscripten/WebGL
Implements Phase 1 of renderer abstraction plan:
- SDL2Types.h: SFML-compatible type stubs in sf:: namespace
- SDL2Renderer.h/cpp: OpenGL ES 2 rendering implementation
- EmscriptenStubs.cpp: Stubs for missing POSIX functions (wait3, wait4, wcsftime)

Build system changes:
- Add MCRF_SDL2 compile-time backend selection
- Add Emscripten SDL2 link options (-sUSE_SDL=2, -sFULL_ES2=1)
- Fix LONG_BIT mismatch for Emscripten in pyport.h

Code changes for SDL2/headless compatibility:
- Guard ImGui includes with !MCRF_HEADLESS && !MCRF_SDL2
- Defer GL shader initialization until after context creation

Current status: Python runs in browser, rendering WIP (canvas sizing issues)

Build commands:
  emcmake cmake -DMCRF_SDL2=ON -B build-emscripten
  emmake make -C build-emscripten

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 11:13:15 -05:00
8c3128e29c WASM Python integration milestone - game.py runs in browser
Major milestone for issue #158 (Emscripten/WebAssembly build target):
- Python 3.14 successfully initializes and runs in WASM
- mcrfpy module loads and works correctly
- Game scripts execute with full level generation
- Entities (boulders, rats, cyclops, spawn points) placed correctly

Key changes:
- CMakeLists.txt: Add 2MB stack, Emscripten link options, preload files
- platform.h: Add WASM-specific implementations for executable paths
- HeadlessTypes.h: Make Texture/Font/Sound stubs return success
- CommandLineParser.cpp: Guard filesystem operations for WASM
- McRFPy_API.cpp: Add WASM path configuration, debug output
- game.py: Make 'code' module import optional (not available in WASM)
- wasm_stdlib/: Add minimal Python stdlib for WASM (~4MB)

Build with: emmake make (from build-emscripten/)
Test with: node mcrogueface.js

Next steps:
- Integrate VRSFML for actual WebGL rendering
- Create HTML page to host WASM build
- Test in actual browsers

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-31 05:15:11 -05:00
7621ae35bb Add MCRF_HEADLESS compile-time build option for #158
This commit enables McRogueFace to compile without SFML dependencies
when built with -DMCRF_HEADLESS, a prerequisite for Emscripten/WebAssembly
support.

Changes:
- Add src/platform/HeadlessTypes.h (~900 lines of SFML type stubs)
- Consolidate all SFML includes through src/Common.h (15 files fixed)
- Wrap ImGui-SFML with #ifndef MCRF_HEADLESS guards
- Disable debug console/explorer in headless builds
- Add comprehensive research document: docs/EMSCRIPTEN_RESEARCH.md

The headless build compiles successfully but uses stub implementations
that return failure/no-op. This proves the abstraction boundary is clean
and enables future work on alternative backends (VRSFML, Emscripten).

What still works in headless mode:
- Python interpreter and script execution
- libtcod integrations (pathfinding, FOV, noise, BSP, heightmaps)
- Timer system and scene management
- All game logic and data structures

Build commands:
  Normal:   make
  Headless: cmake .. -DCMAKE_CXX_FLAGS="-DMCRF_HEADLESS" && make

Addresses #158

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-30 23:09:07 -05:00
486087b9cb Shaders 2026-01-25 21:04:01 -05:00
4ead2f25fe Fix #215: Replace mcrfpy.libtcod with mcrfpy.bresenham()
- Remove mcrfpy.libtcod submodule entirely
- Add mcrfpy.bresenham(start, end, include_start=True, include_end=True)
  - Accepts tuples or Vector objects for positions
  - Returns list of (x, y) tuples along the line
- compute_fov() was redundant with Grid.compute_fov()
- line() functionality now available as top-level bresenham()

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-20 00:10:13 -05:00
257e52327b Fix #219: Add threading support with mcrfpy.lock() context manager
Enables background Python threads to safely modify UI objects by
synchronizing with the render loop at frame boundaries.

Implementation:
- FrameLock class provides mutex/condvar synchronization
- GIL released during window.display() allowing background threads to run
- Safe window opens between frames for synchronized UI updates
- mcrfpy.lock() context manager blocks until safe window, then executes
- Main thread detection: lock() is a no-op when called from callbacks
  or script initialization (already synchronized)

Usage:
    import threading
    import mcrfpy

    def background_worker():
        with mcrfpy.lock():  # Blocks until safe
            player.x = new_x  # Safe to modify UI

    threading.Thread(target=background_worker).start()

The lock works transparently from any context - background threads get
actual synchronization, main thread calls (callbacks, init) get no-op.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-19 23:37:49 -05:00
4bf590749c Alignment: reactive or automatically calculated repositioning of UIDrawables on their parent 2026-01-13 20:40:34 -05:00
8628ac164b BSP: add room adjacency graph for corridor generation (closes #210)
New features:
- bsp.adjacency[i] returns tuple of neighbor leaf indices
- bsp.get_leaf(index) returns BSPNode by leaf index (O(1) lookup)
- node.leaf_index returns this leaf's index (0..n-1) or None
- node.adjacent_tiles[j] returns tuple of Vector wall tiles bordering neighbor j

Implementation details:
- Lazy-computed adjacency cache with generation-based invalidation
- O(n²) pairwise adjacency check on first access
- Wall tiles computed per-direction (not symmetric) for correct perspective
- Supports 'in' operator: `5 in leaf.adjacent_tiles`

Code review fixes applied:
- split_once now increments generation to invalidate cache
- Wall tile cache uses (self, neighbor) key, not symmetric
- Added sq_contains for 'in' operator support
- Documented wall tile semantics (tiles on THIS leaf's boundary)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 23:43:57 -05:00
e5d0eb4847 Noise, combination, and sampling: first pass at #207, #208, #194, #209 2026-01-12 19:01:20 -05:00
8699bba9e6 BSP: add Binary Space Partitioning for procedural dungeon generation
Implements #202, #203, #204, #205; partially implements #206:
- BSP class: core tree structure with bounds, split_once, split_recursive, clear
- BSPNode class: lightweight node reference with bounds, level, is_leaf,
  split_horizontal, split_position; navigation via left/right/parent/sibling;
  contains() and center() methods
- Traversal enum: PRE_ORDER, IN_ORDER, POST_ORDER, LEVEL_ORDER, INVERTED_LEVEL_ORDER
- BSP iteration: leaves() for leaf nodes only, traverse(order) for all nodes
- BSP query: find(pos) returns deepest node containing position
- BSP.to_heightmap(): converts BSP to HeightMap with select, shrink, value options

Note: #206's BSPMap subclass deferred - to_heightmap returns plain HeightMap.
The HeightMap already has all necessary operations (inverse, threshold, etc.)
for procedural generation workflows.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-12 07:02:54 -05:00
c095be4b73 HeightMap: core class with scalar operations (closes #193)
Implement the foundational HeightMap class for procedural generation:

- HeightMap(size, fill=0.0) constructor with libtcod backend
- Immutable size property after construction
- Scalar operations returning self for method chaining:
  - fill(value), clear()
  - add_constant(value), scale(factor)
  - clamp(min=0.0, max=1.0), normalize(min=0.0, max=1.0)

Includes procedural generation spec document and unit tests.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-11 20:07:55 -05:00
b32f5af28c UIGridPathfinding: clear and separate A-star and Djikstra path systems 2026-01-10 22:09:45 -05:00
9eacedc624 Input Enums instead of strings. 2026-01-10 21:31:20 -05:00
d6ef29f3cd Grid code quality improvements
* Grid [x, y] subscript - convenience for `.at()`
* Extract UIEntityCollection - cleanup of UIGrid.cpp
* Thread-safe type cache - PyTypeCache
* Exception-safe extend() - validate before modify
2026-01-10 08:37:31 -05:00
a77ac6c501 Monkey Patch support + Robust callback tracking
McRogueFace needs to accept callable objects (properties on C++ objects)
and also support subclassing (getattr on user objects). Only direct
properties were supported previously, now shadowing a callback by name
will allow custom objects to "just work".
- Added CallbackCache struct and is_python_subclass flag to UIDrawable.h
- Created metaclass for tracking class-level callback changes
- Updated all UI type init functions to detect subclasses
- Modified PyScene.cpp event dispatch to try subclass methods
2026-01-09 21:37:23 -05:00
1438044c6a mingw toolchain and final fixes for Windows. Closes #162 2026-01-08 21:16:27 -05:00
75127ac9d1 mcrfpy.Mouse: a new class built for symmetry with mcrfpy.Keyboard. Closes #186 2026-01-06 21:39:01 -05:00
b0b17f4633 timer fixes: timers managed by engine can run in the background. Closes #180 2026-01-06 20:13:51 -05:00
2c20455003 support for Scene object as parent, from Python: closes #183 2026-01-06 14:04:53 -05:00
f9b6cdef1c Python API improvements: Vectors, bounds, window singleton, hidden types
- #177: GridPoint.grid_pos property returns (x, y) tuple
- #179: Grid.grid_size returns Vector instead of tuple
- #181: Grid.center returns Vector instead of tuple
- #182: Caption.size/w/h read-only properties for text dimensions
- #184: mcrfpy.window singleton for window access
- #185: Removed get_bounds() method, use .bounds property instead
- #188: bounds/global_bounds return (pos, size) as pair of Vectors
- #189: Hide internal types from module namespace (iterators, collections)

Also fixed critical bug: Changed static PyTypeObject to inline in headers
to ensure single instance across translation units (was causing segfaults).

Closes #177, closes #179, closes #181, closes #182, closes #184, closes #185, closes #188, closes #189

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-05 23:00:48 -05:00
d878c8684d Easing functions as enum 2026-01-04 12:59:28 -05:00
5d41292bf6 Timer refactor: stopwatch-like semantics, mcrfpy.timers collection closes #173
Major Timer API improvements:
- Add `stopped` flag to Timer C++ class for proper state management
- Add `start()` method to restart stopped timers (preserves callback)
- Add `stop()` method that removes from engine but preserves callback
- Make `active` property read-write (True=start/resume, False=pause)
- Add `start=True` init parameter to create timers in stopped state
- Add `mcrfpy.timers` module-level collection (tuple of active timers)
- One-shot timers now set stopped=true instead of clearing callback
- Remove deprecated `setTimer()` and `delTimer()` module functions

Timer callbacks now receive (timer, runtime) instead of just (runtime).
Updated all tests to use new Timer API and callback signature.

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

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-03 22:09:18 -05:00
fc95fc2844 scene transitions via Scene object 2026-01-03 13:53:18 -05:00
d7e34a3f72 Remove old scene management methods 2026-01-03 11:01:42 -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
71c91e19a5 feat: Add consistent Scene API with module-level properties (closes #151)
Replaces module-level scene functions with more Pythonic OO interface:

Scene class changes:
- Add `scene.children` property (replaces get_ui() method)
- Add `scene.on_key` getter/setter (matches on_click pattern)
- Remove get_ui() method

Module-level properties:
- Add `mcrfpy.current_scene` (getter returns Scene, setter activates)
- Add `mcrfpy.scenes` (read-only tuple of all Scene objects)

Implementation uses custom module type (McRFPyModuleType) inheriting
from PyModule_Type with tp_setattro for property assignment support.

New usage:
  scene = mcrfpy.Scene("game")
  mcrfpy.current_scene = scene
  scene.on_key = handler
  ui = scene.children

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-22 22:15:03 -05:00
f2f8d6422f Add warning when starting benchmark in headless mode
The benchmark API captures per-frame data from the game loop, which is
bypassed when using step()-based simulation control. This warning
informs users to use Python's time module for headless performance
measurement instead.

Also adds test_headless_benchmark.py which verifies:
- step() and screenshot() don't produce benchmark frames
- Wall-clock timing for headless operations
- Complex scene throughput measurement

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 22:20:19 -05:00
60ffa68d04 feat: Add mcrfpy.step() and synchronous screenshot for headless mode (closes #153)
Implements Python-controlled simulation advancement for headless mode:

- Add mcrfpy.step(dt) to advance simulation by dt seconds
- step(None) advances to next scheduled event (timer/animation)
- Timers use simulation_time in headless mode for deterministic behavior
- automation.screenshot() now renders synchronously in headless mode
  (captures current state, not previous frame)

This enables LLM agent orchestration (#156) by allowing:
- Set perspective, take screenshot, query LLM - all synchronous
- Deterministic simulation control without frame timing issues
- Event-driven advancement with step(None)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 21:56:47 -05:00
018e73590f feat: Implement FOV enum and layer draw_fov for #114 and #113
Phase 1 - FOV Enum System:
- Create PyFOV.h/cpp with mcrfpy.FOV IntEnum (BASIC, DIAMOND, SHADOW, etc.)
- Add mcrfpy.default_fov module property initialized to FOV.BASIC
- Add grid.fov and grid.fov_radius properties for per-grid defaults
- Remove deprecated module-level FOV_* constants (breaking change)

Phase 2 - Layer Operations:
- Implement ColorLayer.fill_rect(pos, size, color) for rectangle fills
- Implement TileLayer.fill_rect(pos, size, index) for tile rectangle fills
- Implement ColorLayer.draw_fov(source, radius, fov, visible, discovered, unknown)
  to paint FOV-based visibility on color layers using parent grid's TCOD map

The FOV enum uses Python's IntEnum for type safety while maintaining
backward compatibility with integer values. Tests updated to use new API.

Addresses #114 (FOV enum), #113 (layer operations)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-12-01 15:18:10 -05:00
4b05a95efe feat: Add dynamic layer system for Grid (closes #147)
Implements ColorLayer and TileLayer classes with z_index ordering:
- ColorLayer: stores RGBA color per cell for overlays, fog of war, etc.
- TileLayer: stores sprite index per cell with optional texture
- z_index < 0: renders below entities
- z_index >= 0: renders above entities

Python API:
- grid.add_layer(type, z_index, texture) - create layer
- grid.remove_layer(layer) - remove layer
- grid.layers - list of layers sorted by z_index
- grid.layer(z_index) - get layer by z_index
- layer.at(x,y) / layer.set(x,y,value) - cell access
- layer.fill(value) - fill entire layer

Layers are allocated separately from UIGridPoint, reducing memory
for grids that don't need all features. Base grid retains walkable/
transparent arrays for TCOD pathfinding.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 21:35:38 -05:00
a7fef2aeb6 feat: Add benchmark logging system for performance analysis (closes #104)
Add Python API for capturing performance data to JSON files:
- mcrfpy.start_benchmark() - start capturing frame data
- mcrfpy.end_benchmark() - stop and return filename
- mcrfpy.log_benchmark(msg) - add log message to current frame

The benchmark system captures per-frame data including:
- Frame timing (frame_time_ms, fps, timestamp)
- Detailed timing breakdown (grid_render, entity_render, python, animation, fov)
- Draw call and element counts
- User log messages attached to frames

Output JSON format supports analysis tools and includes:
- Benchmark metadata (PID, timestamps, duration, total frames)
- Full frame-by-frame metrics array

Also refactors ProfilingMetrics from nested GameEngine struct to
top-level struct for easier forward declaration.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 16:05:55 -05:00
219a559c35 feat: Add dirty flag propagation to all UIDrawables and expand metrics API (#144, #104)
- Add markDirty() calls to setProperty() methods in:
  - UISprite: position, scale, sprite_index changes
  - UICaption: position, font_size, colors, text changes
  - UIGrid: position, size, center, zoom, color changes
  - UILine: thickness, position, endpoints, color changes
  - UICircle: radius, position, colors changes
  - UIArc: radius, angles, position, color changes
  - UIEntity: position changes propagate to parent grid

- Expand getMetrics() Python API to include detailed timing breakdown:
  - grid_render_time, entity_render_time, fov_overlay_time
  - python_time, animation_time
  - grid_cells_rendered, entities_rendered, total_entities

- Add comprehensive benchmark suite (tests/benchmarks/benchmark_suite.py):
  - 6 scenarios: empty, static UI, animated UI, mixed, deep hierarchy, grid stress
  - Automated metrics collection and performance assessment
  - Timing breakdown percentages

This enables proper dirty flag propagation for the upcoming texture caching
system (#144) and provides infrastructure for performance benchmarking (#104).

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-28 15:44:09 -05:00
bbc744f8dc feat: Add self-contained venv support for pip packages (closes #137)
- Set sys.executable in PyConfig for subprocess/pip calls
- Detect sibling venv/ directory and prepend site-packages to sys.path
- Add mcrf_venv.py reference implementation for bootstrapping pip
- Supports both Linux (lib/python3.14/site-packages) and Windows (Lib/site-packages)

Usage: ./mcrogueface -m pip install numpy
Or via Python: mcrf_venv.pip_install("numpy")

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 22:01:09 -05:00
3f6ea4fe33 feat: Add ImGui-based developer console overlay
Integrates Dear ImGui for an in-game debug console that replaces the
blocking Python REPL. Press ~ (grave/tilde) to toggle the console.

Features:
- Python code execution without blocking the game loop
- Output capture with color coding (yellow=input, red=errors, gray=output)
- Expression results show repr() automatically
- Command history navigation with up/down arrows
- Word wrapping for long output lines
- Auto-scroll that doesn't fight manual scrolling
- mcrfpy.setDevConsole(bool) API to disable for shipping

Technical changes:
- Update imgui submodule to v1.89.9 (stable)
- Update imgui-sfml submodule to 2.6.x branch (SFML 2.x compatible)
- Add ImGui sources to CMakeLists.txt with OpenGL dependency
- Integrate ImGui lifecycle into GameEngine
- Add ImGuiConsole class for console overlay

closes #36, closes #65, closes #75

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 20:03:58 -05:00
28396b65c9 feat: Migrate to Python 3.14 (closes #135)
Replace deprecated Python C API calls with modern PyConfig-based initialization:
- PySys_SetArgvEx() -> PyConfig.argv (deprecated since 3.11)
- Py_InspectFlag -> PyConfig.inspect (deprecated since 3.12)

Fix critical memory safety bugs discovered during migration:
- PyColor::from_arg() and PyVector::from_arg() now return new references
  instead of borrowed references, preventing use-after-free when callers
  call Py_DECREF on the result
- GameEngine::testTimers() now holds a local shared_ptr copy during
  callback execution, preventing use-after-free when timer callbacks
  call delTimer() on themselves

Fix double script execution bug with --exec flag:
- Scripts were running twice because GameEngine constructor executed them,
  then main.cpp deleted and recreated the engine
- Now reuses existing engine and just sets auto_exit_after_exec flag

Update test syntax to use keyword arguments for Frame/Caption constructors.

Test results: 127/130 passing (97.7%)

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 17:48:12 -05:00
19ded088b0 feat: Exit on first Python callback exception (closes #133)
By default, McRogueFace now exits with code 1 on the first unhandled
exception in timer, click, key, or animation callbacks. This prevents
repeated exception output that wastes resources in AI-driven development.

Changes:
- Add exit_on_exception config flag (default: true)
- Add --continue-after-exceptions CLI flag to preserve old behavior
- Update exception handlers in Timer, PyCallable, and Animation
- Signal game loop via McRFPy_API atomic flags
- Return proper exit code from main()

Before: Timer exceptions repeated 1000+ times until timeout
After: Single traceback, clean exit with code 1

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-26 10:26:30 -05:00
311dc02f1d feat: Add UILine, UICircle, and UIArc drawing primitives
Implement new UIDrawable-derived classes for vector graphics:

- UILine: Thick line segments using sf::ConvexShape for proper thickness
  - Properties: start, end, color, thickness
  - Supports click detection along the line

- UICircle: Filled and outlined circles using sf::CircleShape
  - Properties: radius, center, fill_color, outline_color, outline
  - Full property system for animations

- UIArc: Arc segments for orbital paths and partial circles
  - Properties: center, radius, start_angle, end_angle, color, thickness
  - Uses sf::VertexArray with TriangleStrip for smooth rendering
  - Supports arbitrary angle spans including negative (reverse) arcs

All primitives integrate with the Python API through mcrfpy module:
- Added to PyObjectsEnum for type identification
- Full getter/setter support for all properties
- Added to UICollection for scene management
- Support for visibility, opacity, z_index, name, and click handling

closes #128, closes #129

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-11-25 21:42:33 -05:00
621d719c25 docs: Phase 3 - Convert 19 module functions to MCRF_FUNCTION macros
Converted all module-level functions in McRFPy_API.cpp to use the MCRF_*
documentation macro system:

Audio functions (7):
- createSoundBuffer, loadMusic, setMusicVolume, setSoundVolume
- playSound, getMusicVolume, getSoundVolume

Scene functions (5):
- sceneUI, currentScene, setScene, createScene, keypressScene

Timer functions (2):
- setTimer, delTimer

Utility functions (5):
- exit, setScale, find, findAll, getMetrics

Each function now uses:
- MCRF_SIG for signatures
- MCRF_DESC for descriptions
- MCRF_ARG for parameters
- MCRF_RETURNS for return values
- MCRF_RAISES for exceptions
- MCRF_NOTE for additional details

Phase 4 assessment: PyCallable.cpp and PythonObjectCache.cpp contain only
internal C++ implementation with no Python API to document.

All conversions tested and verified with test_phase3_docs.py.

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

Co-Authored-By: Claude <noreply@anthropic.com>
2025-10-30 19:38:22 -04:00
6aa4625b76 fix: correct module docstring newline escaping
Fixed module-level docstring in PyModuleDef where double-backslash newlines
(\\n) were appearing as literal "\n" text in help(mcrfpy) output.

Changed from escaped newlines (\\n) to actual newlines (\n) so the C compiler
interprets them correctly.

Before: help(mcrfpy) showed "McRogueFace Python API\\n\\nCore game..."
After:  help(mcrfpy) shows proper formatting with line breaks

The issue was in the PyDoc_STR() macro call - it doesn't interpret escape
sequences, so the string literal itself needs to have proper newlines.
2025-10-30 15:57:17 -04:00
f4343e1e82 Squashed commit of the following: [alpha_presentable]
Author: John McCardle <mccardle.john@gmail.com>
Co-Authored-By: Claude <noreply@anthropic.com>

commit dc47f2474c7b2642d368f9772894aed857527807
    the UIEntity rant

commit 673ca8e1b089ea670257fc04ae1a676ed95a40ed
    I forget when these tests were written, but I want them in the squash merge

commit 70c71565c684fa96e222179271ecb13a156d80ad
    Fix UI object segfault by switching from managed to manual weakref management

    The UI types (Frame, Caption, Sprite, Grid, Entity) were using
    Py_TPFLAGS_MANAGED_WEAKREF while also trying to manually create weakrefs
    for the PythonObjectCache. This is fundamentally incompatible - when
    Python manages weakrefs internally, PyWeakref_NewRef() cannot access the
    weakref list properly, causing segfaults.

    Changed all UI types to use manual weakref management (like PyTimer):
    - Restored weakreflist field in all UI type structures
    - Removed Py_TPFLAGS_MANAGED_WEAKREF from all UI type flags
    - Added tp_weaklistoffset for all UI types in module initialization
    - Initialize weakreflist=NULL in tp_new and init methods
    - Call PyObject_ClearWeakRefs() in dealloc functions

    This allows the PythonObjectCache to continue working correctly,
    maintaining Python object identity for C++ objects across the boundary.

    Fixes segfault when creating UI objects (e.g., Caption, Grid) that was
    preventing tutorial scripts from running.

This is the bulk of the required behavior for Issue #126.
that issure isn't ready for closure yet; several other sub-issues left.
    closes #110
    mention issue #109 - resolves some __init__ related nuisances

commit 3dce3ec539ae99e32d869007bf3f49d03e4e2f89
    Refactor timer system for cleaner architecture and enhanced functionality

    Major improvements to the timer system:
    - Unified all timer logic in the Timer class (C++)
    - Removed PyTimerCallable subclass, now using PyCallable directly
    - Timer objects are now passed to callbacks as first argument
    - Added 'once' parameter for one-shot timers that auto-stop
    - Implemented proper PythonObjectCache integration with weakref support

    API enhancements:
    - New callback signature: callback(timer, runtime) instead of just (runtime)
    - Timer objects expose: name, interval, remaining, paused, active, once properties
    - Methods: pause(), resume(), cancel(), restart()
    - Comprehensive documentation with examples
    - Enhanced repr showing timer state (active/paused/once/remaining time)

    This cleanup follows the UIEntity/PyUIEntity pattern and makes the timer
    system more Pythonic while maintaining backward compatibility through
    the legacy setTimer/delTimer API.

    closes #121

commit 145834cfc31b8dabc4cb3591b9cb4ed99fc8b964
    Implement Python object cache to preserve derived types in collections

    Add a global cache system that maintains weak references to Python objects,
    ensuring that derived Python classes maintain their identity when stored in
    and retrieved from C++ collections.

    Key changes:
    - Add PythonObjectCache singleton with serial number system
    - Each cacheable object (UIDrawable, UIEntity, Timer, Animation) gets unique ID
    - Cache stores weak references to prevent circular reference memory leaks
    - Update all UI type definitions to support weak references (Py_TPFLAGS_MANAGED_WEAKREF)
    - Enable subclassing for all UI types (Py_TPFLAGS_BASETYPE)
    - Collections check cache before creating new Python wrappers
    - Register objects in cache during __init__ methods
    - Clean up cache entries in C++ destructors

    This ensures that Python code like:
    ```python
    class MyFrame(mcrfpy.Frame):
        def __init__(self):
            super().__init__()
            self.custom_data = "preserved"

    frame = MyFrame()
    scene.ui.append(frame)
    retrieved = scene.ui[0]  # Same MyFrame instance with custom_data intact
    ```

    Works correctly, with retrieved maintaining the derived type and custom attributes.

    Closes #112

commit c5e7e8e298
    Update test demos for new Python API and entity system

    - Update all text input demos to use new Entity constructor signature
    - Fix pathfinding showcase to work with new entity position handling
    - Remove entity_waypoints tracking in favor of simplified movement
    - Delete obsolete exhaustive_api_demo.py (superseded by newer demos)
    - Adjust entity creation calls to match Entity((x, y), texture, sprite_index) pattern

commit 6d29652ae7
    Update animation demo suite with crash fixes and improvements

    - Add warnings about AnimationManager segfault bug in sizzle_reel_final.py
    - Create sizzle_reel_final_fixed.py that works around the crash by hiding objects instead of removing them
    - Increase font sizes for better visibility in demos
    - Extend demo durations for better showcase of animations
    - Remove debug prints from animation_sizzle_reel_working.py
    - Minor cleanup and improvements to all animation demos

commit a010e5fa96
    Update game scripts for new Python API

    - Convert entity position access from tuple to x/y properties
    - Update caption size property to font_size
    - Fix grid boundary checks to use grid_size instead of exceptions
    - Clean up demo timer on menu exit to prevent callbacks

    These changes adapt the game scripts to work with the new standardized
    Python API constructors and property names.

commit 9c8d6c4591
    Fix click event z-order handling in PyScene

    Changed click detection to properly respect z-index by:
    - Sorting ui_elements in-place when needed (same as render order)
    - Using reverse iterators to check highest z-index elements first
    - This ensures top-most elements receive clicks before lower ones

commit dcd1b0ca33
    Add roguelike tutorial implementation files

    Implement Parts 0-2 of the classic roguelike tutorial adapted for McRogueFace:
    - Part 0: Basic grid setup and tile rendering
    - Part 1: Drawing '@' symbol and basic movement
    - Part 1b: Variant with sprite-based player
    - Part 2: Entity system and NPC implementation with three movement variants:
      - part_2.py: Standard implementation
      - part_2-naive.py: Naive movement approach
      - part_2-onemovequeued.py: Queued movement system

    Includes tutorial assets:
    - tutorial2.png: Tileset for dungeon tiles
    - tutorial_hero.png: Player sprite sheet

commit 6813fb5129
    Standardize Python API constructors and remove PyArgHelpers

    - Remove PyArgHelpers.h and all macro-based argument parsing
    - Convert all UI class constructors to use PyArg_ParseTupleAndKeywords
    - Standardize constructor signatures across UICaption, UIEntity, UIFrame, UIGrid, and UISprite
    - Replace PYARGHELPER_SINGLE/MULTI macros with explicit argument parsing
    - Improve error messages and argument validation
    - Maintain backward compatibility with existing Python code

    This change improves code maintainability and consistency across the Python API.

commit 6f67fbb51e
    Fix animation callback crashes from iterator invalidation (#119)

    Resolved segfaults caused by creating new animations from within
    animation callbacks. The issue was iterator invalidation in
    AnimationManager::update() when callbacks modified the active
    animations vector.

    Changes:
    - Add deferred animation queue to AnimationManager
    - New animations created during update are queued and added after
    - Set isUpdating flag to track when in update loop
    - Properly handle Animation destructor during callback execution
    - Add clearCallback() method for safe cleanup scenarios

    This fixes the "free(): invalid pointer" and "malloc(): unaligned
    fastbin chunk detected" errors that occurred with rapid animation
    creation in callbacks.

commit eb88c7b3aa
    Add animation completion callbacks (#119)

    Implement callbacks that fire when animations complete, enabling direct
    causality between animation end and game state changes. This eliminates
    race conditions from parallel timer workarounds.

    - Add optional callback parameter to Animation constructor
    - Callbacks execute synchronously when animation completes
    - Proper Python reference counting with GIL safety
    - Callbacks receive (anim, target) parameters (currently None)
    - Exception handling prevents crashes from Python errors

    Example usage:
    ```python
    def on_complete(anim, target):
        player_moving = False

    anim = mcrfpy.Animation("x", 300.0, 1.0, "easeOut", callback=on_complete)
    anim.start(player)
    ```

    closes #119

commit 9fb428dd01
    Update ROADMAP with GitHub issue numbers (#111-#125)

    Added issue numbers from GitHub tracker to roadmap items:
    - #111: Grid Click Events Broken in Headless
    - #112: Object Splitting Bug (Python type preservation)
    - #113: Batch Operations for Grid
    - #114: CellView API
    - #115: SpatialHash Implementation
    - #116: Dirty Flag System
    - #117: Memory Pool for Entities
    - #118: Scene as Drawable
    - #119: Animation Completion Callbacks
    - #120: Animation Property Locking
    - #121: Timer Object System
    - #122: Parent-Child UI System
    - #123: Grid Subgrid System
    - #124: Grid Point Animation
    - #125: GitHub Issues Automation

    Also updated existing references:
    - #101/#110: Constructor standardization
    - #109: Vector class indexing

    Note: Tutorial-specific items and Python-implementable features
    (input queue, collision reservation) are not tracked as engine issues.

commit 062e4dadc4
    Fix animation segfaults with RAII weak_ptr implementation

    Resolved two critical segmentation faults in AnimationManager:
    1. Race condition when creating multiple animations in timer callbacks
    2. Exit crash when animations outlive their target objects

    Changes:
    - Replace raw pointers with std::weak_ptr for automatic target invalidation
    - Add Animation::complete() to jump animations to final value
    - Add Animation::hasValidTarget() to check if target still exists
    - Update AnimationManager to auto-remove invalid animations
    - Add AnimationManager::clear() call to GameEngine::cleanup()
    - Update Python bindings to pass shared_ptr instead of raw pointers

    This ensures animations can never reference destroyed objects, following
    proper RAII principles. Tested with sizzle_reel_final.py and stress
    tests creating/destroying hundreds of animated objects.

commit 98fc49a978
    Directory structure cleanup and organization overhaul
2025-07-15 21:30:49 -04:00
d11f76ac43 Squashed commit of 53 Commits: [alpha_streamline_2]
* Field of View, Pathing courtesy of libtcod
* python-tcod emulation at `mcrfpy.libtcod` - partial implementation
* documentation, tutorial drafts: in middling to good shape

┌────────────┬────────────────────┬───────────┬────────────┬───────────────┬────────────────┬────────────────┬─────────────┐
│ Date       │ Models             │     Input │     Output │  Cache Create │     Cache Read │   Total Tokens │  Cost (USD) │
├────────────┼────────────────────┼───────────┼────────────┼───────────────┼────────────────┼────────────────┼─────────────┤
│ 2025-07-05 │ - opus-4           │    13,630 │    159,500 │     3,854,900 │     84,185,034 │     88,213,064 │     $210.72 │
├────────────┼────────────────────┼───────────┼────────────┼───────────────┼────────────────┼────────────────┼─────────────┤
│ 2025-07-06 │ - opus-4           │     5,814 │    113,190 │     4,242,407 │    150,191,183 │    154,552,594 │     $313.41 │
├────────────┼────────────────────┼───────────┼────────────┼───────────────┼────────────────┼────────────────┼─────────────┤
│ 2025-07-07 │ - opus-4           │     7,244 │    104,599 │     3,894,453 │     81,781,179 │     85,787,475 │     $184.46 │
│            │ - sonnet-4         │           │            │               │                │                │             │
├────────────┼────────────────────┼───────────┼────────────┼───────────────┼────────────────┼────────────────┼─────────────┤
│ 2025-07-08 │ - opus-4           │    50,312 │    158,599 │     5,021,189 │     60,028,561 │     65,258,661 │     $167.05 │
│            │ - sonnet-4         │           │            │               │                │                │             │
├────────────┼────────────────────┼───────────┼────────────┼───────────────┼────────────────┼────────────────┼─────────────┤
│ 2025-07-09 │ - opus-4           │     6,311 │    109,653 │     4,171,140 │     80,092,875 │     84,379,979 │     $193.09 │
│            │ - sonnet-4         │           │            │               │                │                │             │
└────────────┴────────────────────┴───────────┴────────────┴───────────────┴────────────────┴────────────────┴─────────────┘

    🤖 Generated with [Claude Code](https://claude.ai/code)
    Co-Authored-By: Claude <noreply@anthropic.com>

Author: John McCardle <mccardle.john@gmail.com>

    Draft tutorials

Author: John McCardle <mccardle.john@gmail.com>

    docs: update ROADMAP with FOV, A* pathfinding, and GUI text widget completions

    - Mark TCOD Integration Sprint as complete
    - Document FOV system with perspective rendering implementation
    - Update UIEntity pathfinding status to complete with A* and caching
    - Add comprehensive achievement entry for July 10 work
    - Reflect current engine capabilities accurately

    The engine now has all core roguelike mechanics:
    - Field of View with per-entity visibility
    - Pathfinding (both Dijkstra and A*)
    - Text input for in-game consoles
    - Performance optimizations throughout

Author: John McCardle <mccardle.john@gmail.com>

    feat(engine): implement perspective FOV, pathfinding, and GUI text widgets

    Major Engine Enhancements:
    - Complete FOV (Field of View) system with perspective rendering
      - UIGrid.perspective property for entity-based visibility
      - Three-layer overlay colors (unexplored, explored, visible)
      - Per-entity visibility state tracking
      - Perfect knowledge updates only for explored areas

    - Advanced Pathfinding Integration
      - A* pathfinding implementation in UIGrid
      - Entity.path_to() method for direct pathfinding
      - Dijkstra maps for multi-target pathfinding
      - Path caching for performance optimization

    - GUI Text Input Widgets
      - TextInputWidget class with cursor, selection, scrolling
      - Improved widget with proper text rendering and input handling
      - Example showcase of multiple text input fields
      - Foundation for in-game console and chat systems

    - Performance & Architecture Improvements
      - PyTexture copy operations optimized
      - GameEngine update cycle refined
      - UIEntity property handling enhanced
      - UITestScene modernized

    Test Suite:
    - Interactive visibility demos showing FOV in action
    - Pathfinding comparison (A* vs Dijkstra)
    - Debug utilities for visibility and empty path handling
    - Sizzle reel demo combining pathfinding and vision
    - Multiple text input test scenarios

    This commit brings McRogueFace closer to a complete roguelike engine
    with essential features like line-of-sight, intelligent pathfinding,
    and interactive text input capabilities.

Author: John McCardle <mccardle.john@gmail.com>

    feat(demos): enhance interactive pathfinding demos with entity.path_to()

    - dijkstra_interactive_enhanced.py: Animation along paths with smooth movement
      - M key to start movement animation
      - P to pause/resume
      - R to reset positions
      - Visual path gradient for better clarity

    - pathfinding_showcase.py: Advanced multi-entity behaviors
      - Chase mode: enemies pursue player
      - Flee mode: enemies avoid player
      - Patrol mode: entities follow waypoints
      - WASD player movement
      - Dijkstra distance field visualization (D key)
      - Larger dungeon map with multiple rooms

    - Both demos use new entity.path_to() method
    - Smooth interpolated movement animations
    - Real-time pathfinding recalculation
    - Comprehensive test coverage

    These demos showcase the power of integrated pathfinding for game AI.

Author: John McCardle <mccardle.john@gmail.com>

    feat(entity): implement path_to() method for entity pathfinding

    - Add path_to(target_x, target_y) method to UIEntity class
    - Uses existing Dijkstra pathfinding implementation from UIGrid
    - Returns list of (x, y) coordinate tuples for complete path
    - Supports both positional and keyword argument formats
    - Proper error handling for out-of-bounds and no-grid scenarios
    - Comprehensive test suite covering normal and edge cases

    Part of TCOD integration sprint - gives entities immediate pathfinding capabilities.

Author: John McCardle <mccardle.john@gmail.com>

    docs: update roadmap with Dijkstra pathfinding progress

    - Mark UIGrid TCOD Integration as completed
    - Document critical PyArg bug fix achievement
    - Update UIEntity Pathfinding to 50% complete
    - Add detailed progress notes for July 9 sprint work

Author: John McCardle <mccardle.john@gmail.com>

    feat(tcod): complete Dijkstra pathfinding implementation with critical PyArg fix

    - Add complete Dijkstra pathfinding to UIGrid class
      - compute_dijkstra(), get_dijkstra_distance(), get_dijkstra_path()
      - Full TCODMap and TCODDijkstra integration
      - Proper memory management in constructors/destructors

    - Create mcrfpy.libtcod submodule with Python bindings
      - dijkstra_compute(), dijkstra_get_distance(), dijkstra_get_path()
      - line() function for drawing corridors
      - Foundation for future FOV and pathfinding algorithms

    - Fix critical PyArg bug in UIGridPoint color setter
      - PyObject_to_sfColor() now handles both Color objects and tuples
      - Prevents "SystemError: new style getargs format but argument is not a tuple"
      - Proper error handling and exception propagation

    - Add comprehensive test suite
      - test_dijkstra_simple.py validates all pathfinding operations
      - dijkstra_test.py for headless testing with screenshots
      - dijkstra_interactive.py for full user interaction demos

    - Consolidate and clean up test files
      - Removed 6 duplicate/broken demo attempts
      - Two clean versions: headless test + interactive demo

    Part of TCOD integration sprint for RoguelikeDev Tutorial Event.

Author: John McCardle <mccardle.john@gmail.com>

    Roguelike Tutorial Planning + Prep

Author: John McCardle <mccardle.john@gmail.com>

    feat(docs): complete markdown API documentation export

    - Created comprehensive markdown documentation matching HTML completeness
    - Documented all 75 functions, 20 classes, 56 methods, and 20 automation methods
    - Zero ellipsis instances - complete coverage with no missing documentation
    - Added proper markdown formatting with code blocks and navigation
    - Included full parameter documentation, return values, and examples

    Key features:
    - 23KB GitHub-compatible markdown documentation
    - 47 argument sections with detailed parameters
    - 35 return value specifications
    - 23 code examples with syntax highlighting
    - 38 explanatory notes and 10 exception specifications
    - Full table of contents with anchor links
    - Professional markdown formatting

    Both export formats now available:
    - HTML: docs/api_reference_complete.html (54KB, rich styling)
    - Markdown: docs/API_REFERENCE_COMPLETE.md (23KB, GitHub-compatible)

Author: John McCardle <mccardle.john@gmail.com>

    feat(docs): complete API documentation with zero missing methods

    - Eliminated ALL ellipsis instances (0 remaining)
    - Documented 40 functions with complete signatures and examples
    - Documented 21 classes with full method and property documentation
    - Added 56 method descriptions with detailed parameters and return values
    - Included 15 complete property specifications
    - Added 24 code examples and 38 explanatory notes
    - Comprehensive coverage of all collection methods, system classes, and functions

    Key highlights:
    - EntityCollection/UICollection: Complete method docs (append, remove, extend, count, index)
    - Animation: Full property and method documentation with examples
    - Color: All manipulation methods (from_hex, to_hex, lerp) with examples
    - Vector: Complete mathematical operations (magnitude, normalize, dot, distance_to, angle, copy)
    - Scene: All management methods including register_keyboard
    - Timer: Complete control methods (pause, resume, cancel, restart)
    - Window: All management methods (get, center, screenshot)
    - System functions: Complete audio, scene, UI, and system function documentation

Author: John McCardle <mccardle.john@gmail.com>

    feat(docs): create professional HTML API documentation

    - Fixed all formatting issues from original HTML output
    - Added comprehensive constructor documentation for all classes
    - Enhanced visual design with modern styling and typography
    - Fixed literal newline display and markdown link conversion
    - Added proper semantic HTML structure and navigation
    - Includes detailed documentation for Entity, collections, and system types

Author: John McCardle <mccardle.john@gmail.com>

    feat: complete API reference generator and finish Phase 7 documentation

    Implemented comprehensive API documentation generator that:
    - Introspects live mcrfpy module for accurate documentation
    - Generates organized Markdown reference (docs/API_REFERENCE.md)
    - Categorizes classes and functions by type
    - Includes full automation module documentation
    - Provides summary statistics

    Results:
    - 20 classes documented
    - 19 module functions documented
    - 20 automation methods documented
    - 100% coverage of public API
    - Clean, readable Markdown output

    Phase 7 Summary:
    - Completed 4/5 tasks (1 cancelled as architecturally inappropriate)
    - All documentation tasks successful
    - Type stubs, docstrings, and API reference all complete

Author: John McCardle <mccardle.john@gmail.com>

    docs: cancel PyPI wheel task and add future vision for Python extension architecture

    Task #70 Analysis:
    - Discovered fundamental incompatibility with PyPI distribution
    - McRogueFace embeds CPython rather than being loaded by it
    - Traditional wheels expect to extend existing Python interpreter
    - Current architecture is application-with-embedded-Python

    Decisions:
    - Cancelled PyPI wheel preparation as out of scope for Alpha
    - Cleaned up attempted packaging files (pyproject.toml, setup.py, etc.)
    - Identified better distribution methods (installers, package managers)

    Added Future Vision:
    - Comprehensive plan for pure Python extension architecture
    - Would allow true "pip install mcrogueface" experience
    - Requires major refactoring to invert control flow
    - Python would drive main loop with C++ performance extensions
    - Unscheduled but documented as long-term possibility

    This clarifies the architectural boundaries and sets realistic
    expectations for distribution methods while preserving the vision
    of what McRogueFace could become with significant rework.

Author: John McCardle <mccardle.john@gmail.com>

    feat: generate comprehensive .pyi type stubs for IDE support (#108)

    Created complete type stub files for the mcrfpy module to enable:
    - Full IntelliSense/autocomplete in IDEs
    - Static type checking with mypy/pyright
    - Better documentation tooltips
    - Parameter hints and return types

    Implementation details:
    - Manually crafted stubs for accuracy (15KB, 533 lines)
    - Complete coverage: 19 classes, 112 functions/methods
    - Proper type annotations using typing module
    - @overload decorators for multiple signatures
    - Type aliases for common patterns (UIElement union)
    - Preserved all docstrings for IDE help
    - Automation module fully typed
    - PEP 561 compliant with py.typed marker

    Testing:
    - Validated Python syntax with ast.parse()
    - Verified all expected classes and functions
    - Confirmed type annotations are well-formed
    - Checked docstring preservation (80 docstrings)

    Usage:
    - VS Code: Add stubs/ to python.analysis.extraPaths
    - PyCharm: Mark stubs/ directory as Sources Root
    - Other IDEs will auto-detect .pyi files

    This significantly improves the developer experience when using
    McRogueFace as a Python game engine.

Author: John McCardle <mccardle.john@gmail.com>

    docs: add comprehensive parameter documentation to all API methods (#86)

    Enhanced documentation for the mcrfpy module with:
    - Detailed docstrings for all API methods
    - Type hints in documentation (name: type format)
    - Return type specifications
    - Exception documentation where applicable
    - Usage examples for complex methods
    - Module-level documentation with overview and example code

    Specific improvements:
    - Audio API: Added parameter types and return values
    - Scene API: Documented transition types and error conditions
    - Timer API: Clarified handler signature and runtime parameter
    - UI Search: Added wildcard pattern examples for findAll()
    - Metrics API: Documented all dictionary keys returned

    Also fixed method signatures:
    - Changed METH_VARARGS to METH_NOARGS for parameterless methods
    - Ensures proper Python calling conventions

    Test coverage included - all documentation is accessible via Python's
    __doc__ attributes and shows correctly formatted information.

Author: John McCardle <mccardle.john@gmail.com>

    docs: mark issue #85 as completed in Phase 7

Author: John McCardle <mccardle.john@gmail.com>

    docs: replace all 'docstring' placeholders with comprehensive documentation (#85)

    Added proper Python docstrings for all UI component classes:

    UIFrame:
    - Container element that can hold child drawables
    - Documents position, size, colors, outline, and clip_children
    - Includes constructor signature with all parameters

    UICaption:
    - Text display element with font and styling
    - Documents text content, position, font, colors, outline
    - Notes that w/h are computed from text content

    UISprite:
    - Texture/sprite display element
    - Documents position, texture, sprite_index, scale
    - Notes that w/h are computed from texture and scale

    UIGrid:
    - Tile-based grid for game worlds
    - Documents grid dimensions, tile size, texture atlas
    - Includes entities collection and background_color

    All docstrings follow consistent format:
    - Constructor signature with defaults
    - Brief description
    - Args section with types and defaults
    - Attributes section with all properties

    This completes Phase 7 task #85 for documentation improvements.

Author: John McCardle <mccardle.john@gmail.com>

    docs: update ROADMAP with PyArgHelpers infrastructure completion

Author: John McCardle <mccardle.john@gmail.com>

    refactor: implement PyArgHelpers for standardized Python argument parsing

    This major refactoring standardizes how position, size, and other arguments
    are parsed across all UI components. PyArgHelpers provides consistent handling
    for various argument patterns:

    - Position as (x, y) tuple or separate x, y args
    - Size as (w, h) tuple or separate width, height args
    - Grid position and size with proper validation
    - Color parsing with PyColorObject support

    Changes across UI components:
    - UICaption: Migrated to PyArgHelpers, improved resize() for future multiline support
    - UIFrame: Uses standardized position parsing
    - UISprite: Consistent position handling
    - UIGrid: Grid-specific position/size helpers
    - UIEntity: Unified argument parsing

    Also includes:
    - Improved error messages for type mismatches (int or float accepted)
    - Reduced code duplication across constructors
    - Better handling of keyword/positional argument conflicts
    - Maintains backward compatibility with existing API

    This addresses the inconsistent argument handling patterns discovered during
    the inheritance hierarchy work and prepares for Phase 7 documentation.

Author: John McCardle <mccardle.john@gmail.com>

    feat(Python): establish proper inheritance hierarchy for UI types

    All UIDrawable-derived Python types now properly inherit from the Drawable
    base class in Python, matching the C++ inheritance structure.

    Changes:
    - Add Py_TPFLAGS_BASETYPE to PyDrawableType to allow inheritance
    - Set tp_base = &mcrfpydef::PyDrawableType for all UI types
    - Add PyDrawable.h include to UI type headers
    - Rename _Drawable to Drawable and update error message

    This enables proper Python inheritance: Frame, Caption, Sprite, Grid,
    and Entity all inherit from Drawable, allowing shared functionality
    and isinstance() checks.

Author: John McCardle <mccardle.john@gmail.com>

    refactor: move position property to UIDrawable base class (UISprite)

    - Update UISprite to use base class position instead of sprite position
    - Synchronize sprite position with base class position for rendering
    - Implement onPositionChanged() for position synchronization
    - Update all UISprite methods to use base position consistently
    - Add comprehensive test coverage for UISprite position handling

    This is part 3 of moving position to the base class. UIGrid is the final
    class that needs to be updated.

Author: John McCardle <mccardle.john@gmail.com>

    refactor: move position property to UIDrawable base class (UICaption)

    - Update UICaption to use base class position instead of text position
    - Synchronize text position with base class position for rendering
    - Add onPositionChanged() virtual method for position synchronization
    - Update all UICaption methods to use base position consistently
    - Add comprehensive test coverage for UICaption position handling

    This is part 2 of moving position to the base class. UISprite and UIGrid
    will be updated in subsequent commits.

Author: John McCardle <mccardle.john@gmail.com>

    refactor: move position property to UIDrawable base class (UIFrame)

    - Add position member to UIDrawable base class
    - Add common position getters/setters (x, y, pos) to base class
    - Update UIFrame to use base class position instead of box position
    - Synchronize box position with base class position for rendering
    - Update all UIFrame methods to use base position consistently
    - Add comprehensive test coverage for UIFrame position handling

    This is part 1 of moving position to the base class. Other derived classes
    (UICaption, UISprite, UIGrid) will be updated in subsequent commits.

Author: John McCardle <mccardle.john@gmail.com>

    refactor: remove UIEntity collision_pos field

    - Remove redundant collision_pos field from UIEntity
    - Update position getters/setters to use integer-cast position when needed
    - Remove all collision_pos synchronization code
    - Simplify entity position handling to use single float position field
    - Add comprehensive test coverage proving functionality is preserved

    This removes technical debt and simplifies the codebase without changing API behavior.

Author: John McCardle <mccardle.john@gmail.com>

    feat: add PyArgHelpers infrastructure for standardized argument parsing

    - Create PyArgHelpers.h with parsing functions for position, size, grid coordinates, and color
    - Support tuple-based vector arguments with conflict detection
    - Provide consistent error messages and validation
    - Add comprehensive test coverage for infrastructure

    This sets the foundation for standardizing all Python API constructors.

Author: John McCardle <mccardle.john@gmail.com>

    docs: mark Phase 6 (Rendering Revolution) as complete

    Phase 6 is now complete with all core rendering features implemented:

    Completed Features:
    - Grid background colors (#50) - customizable backgrounds with animation
    - RenderTexture overhaul (#6) - UIFrame clipping with opt-in architecture
    - Viewport-based rendering (#8) - three scaling modes with coordinate transform

    Strategic Decisions:
    - UIGrid already has optimal RenderTexture implementation for its viewport needs
    - UICaption/UISprite clipping deemed unnecessary (no children to clip)
    - Effects/Shader/Particle systems deferred to post-Phase 7 for focused delivery

    The rendering foundation is now solid and ready for Phase 7: Documentation & Distribution.

Author: John McCardle <mccardle.john@gmail.com>

    feat(viewport): complete viewport-based rendering system (#8)

    Implements a comprehensive viewport system that allows fixed game resolution
    with flexible window scaling, addressing the primary wishes for issues #34, #49, and #8.

    Key Features:
    - Fixed game resolution independent of window size (window.game_resolution property)
    - Three scaling modes accessible via window.scaling_mode:
      - "center": 1:1 pixels, viewport centered in window
      - "stretch": viewport fills window, ignores aspect ratio
      - "fit": maintains aspect ratio with black bars
    - Automatic window-to-game coordinate transformation for mouse input
    - Full Python API integration with PyWindow properties

    Technical Implementation:
    - GameEngine::ViewportMode enum with Center, Stretch, Fit modes
    - SFML View system for efficient GPU-based viewport scaling
    - updateViewport() recalculates on window resize or mode change
    - windowToGameCoords() transforms mouse coordinates correctly
    - PyScene mouse input automatically uses transformed coordinates

    Tests:
    - test_viewport_simple.py: Basic API functionality
    - test_viewport_visual.py: Visual verification with screenshots
    - test_viewport_scaling.py: Interactive mode switching and resizing

    This completes the viewport-based rendering task and provides the foundation
    for resolution-independent game development as requested for Crypt of Sokoban.

Author: John McCardle <mccardle.john@gmail.com>

    docs: update ROADMAP for Phase 6 progress

    - Marked Phase 6 as IN PROGRESS
    - Updated RenderTexture overhaul (#6) as PARTIALLY COMPLETE
    - Marked Grid background colors (#50) as COMPLETED
    - Added technical notes from implementation experience
    - Identified viewport rendering (#8) as next priority

Author: John McCardle <mccardle.john@gmail.com>

    feat(rendering): implement RenderTexture base infrastructure and UIFrame clipping (#6)

    - Added RenderTexture support to UIDrawable base class
      - std::unique_ptr<sf::RenderTexture> for opt-in rendering
      - Dirty flag system for optimization
      - enableRenderTexture() and markDirty() methods

    - Implemented clip_children property for UIFrame
      - Python-accessible boolean property
      - Automatic RenderTexture creation when enabled
      - Proper coordinate transformation for nested frames

    - Updated UIFrame::render() for clipping support
      - Renders to RenderTexture when clip_children=true
      - Handles nested clipping correctly
      - Only re-renders when dirty flag is set

    - Added comprehensive dirty flag propagation
      - All property setters mark frame as dirty
      - Size changes recreate RenderTexture
      - Animation system integration

    - Created tests for clipping functionality
      - Basic clipping test with visual verification
      - Advanced nested clipping test
      - Dynamic resize handling test

    This is Phase 1 of the RenderTexture overhaul, providing the foundation
    for advanced rendering effects like blur, glow, and viewport rendering.

Author: John McCardle <mccardle.john@gmail.com>

    docs: create RenderTexture overhaul design document

    - Comprehensive design for Issue #6 implementation
    - Opt-in architecture to maintain backward compatibility
    - Phased implementation plan with clear milestones
    - Performance considerations and risk mitigation
    - API design for clipping and future effects

    Also includes Grid background color test

Author: John McCardle <mccardle.john@gmail.com>

    feat(Grid): add customizable background_color property (#50)

    - Added sf::Color background_color member with default dark gray
    - Python property getter/setter for background_color
    - Animation support for individual color components (r/g/b/a)
    - Replaces hardcoded clear color in render method
    - Test demonstrates color changes and property access

    Closes #50

Author: John McCardle <mccardle.john@gmail.com>

    docs: update roadmap for Phase 6 preparation

    - Mark Phase 5 (Window/Scene Architecture) as complete
    - Update issue statuses (#34, #61, #1, #105 completed)
    - Add Phase 6 implementation strategy for RenderTexture overhaul
    - Archive Phase 5 test files to .archive/
    - Identify quick wins and technical approach for rendering work

Author: John McCardle <mccardle.john@gmail.com>

    feat(Phase 5): Complete Window/Scene Architecture

    - Window singleton with properties (resolution, fullscreen, vsync, title)
    - OOP Scene support with lifecycle methods (on_enter, on_exit, on_keypress, update)
    - Window resize events trigger scene.on_resize callbacks
    - Scene transitions (fade, slide_left/right/up/down) with smooth animations
    - Full integration of Python Scene objects with C++ engine

    All Phase 5 tasks (#34, #1, #61, #105) completed successfully.

Author: John McCardle <mccardle.john@gmail.com>

    research: SFML 3.0 migration analysis

    - Analyzed SFML 3.0 breaking changes (event system, scoped enums, C++17)
    - Assessed migration impact on McRogueFace (40+ files affected)
    - Evaluated timing relative to mcrfpy.sfml module plans
    - Recommended deferring migration until after mcrfpy.sfml implementation
    - Created SFML_3_MIGRATION_RESEARCH.md with comprehensive strategy

Author: John McCardle <mccardle.john@gmail.com>

    research: SFML exposure options analysis (#14)

    - Analyzed current SFML 2.6.1 usage throughout codebase
    - Evaluated python-sfml (abandoned, only supports SFML 2.3.2)
    - Recommended direct integration as mcrfpy.sfml module
    - Created comprehensive SFML_EXPOSURE_RESEARCH.md with implementation plan
    - Identified opportunity to provide modern SFML 2.6+ Python bindings

Author: John McCardle <mccardle.john@gmail.com>

    feat: add basic profiling/metrics system (#104)

    - Add ProfilingMetrics struct to track performance data
    - Track frame time (current and 60-frame rolling average)
    - Calculate FPS from average frame time
    - Count draw calls, UI elements, and visible elements per frame
    - Track total runtime and current frame number
    - PyScene counts elements during render
    - Expose metrics via mcrfpy.getMetrics() returning dict

    This provides basic performance monitoring capabilities for
    identifying bottlenecks and optimizing rendering performance.

Author: John McCardle <mccardle.john@gmail.com>

    fix: improve click handling with proper z-order and coordinate transforms

    - UIFrame: Fix coordinate transformation (subtract parent pos, not add)
    - UIFrame: Check children in reverse order (highest z-index first)
    - UIFrame: Skip invisible elements entirely
    - PyScene: Sort elements by z-index before checking clicks
    - PyScene: Stop at first element that handles the click
    - UIGrid: Implement entity click detection with grid coordinate transform
    - UIGrid: Check entities in reverse order, return sprite as target

    Click events now correctly respect z-order (top elements get priority),
    handle coordinate transforms for nested frames, and support clicking
    on grid entities. Elements without click handlers are transparent to
    clicks, allowing elements below to receive them.

    Note: Click testing requires non-headless mode due to PyScene limitation.

    feat: implement name system for finding UI elements (#39/40/41)

    - Add 'name' property to UIDrawable base class
    - All UI elements (Frame, Caption, Sprite, Grid, Entity) support .name
    - Entity delegates name to its sprite member
    - Add find(name, scene=None) function for exact match search
    - Add findAll(pattern, scene=None) with wildcard support (* matches any sequence)
    - Both functions search recursively through Frame children and Grid entities
    - Comprehensive test coverage for all functionality

    This provides a simple way to find UI elements by name in Python scripts,
    supporting both exact matches and wildcard patterns.

Author: John McCardle <mccardle.john@gmail.com>

    fix: prevent segfault when closing window via X button

    - Add cleanup() method to GameEngine to clear Python references before destruction
    - Clear timers and McRFPy_API references in proper order
    - Call cleanup() at end of run loop and in destructor
    - Ensure cleanup is only called once per GameEngine instance

    Also includes:
    - Fix audio ::stop() calls (already in place, OpenAL warning is benign)
    - Add Caption support for x, y keywords (e.g. Caption("text", x=5, y=10))
    - Refactor UIDrawable_methods.h into UIBase.h for better organization
    - Move UIEntity-specific implementations to UIEntityPyMethods.h

Author: John McCardle <mccardle.john@gmail.com>

    feat: stabilize test suite and add UIDrawable methods

    - Add visible, opacity properties to all UI classes (#87, #88)
    - Add get_bounds(), move(), resize() methods to UIDrawable (#89, #98)
    - Create UIDrawable_methods.h with template implementations
    - Fix test termination issues - all tests now exit properly
    - Fix test_sprite_texture_swap.py click handler signature
    - Fix test_drawable_base.py segfault in headless mode
    - Convert audio objects to pointers for cleanup (OpenAL warning persists)
    - Remove debug print statements from UICaption
    - Special handling for UIEntity to delegate drawable methods to sprite

    All test files are now "airtight" - they complete successfully,
    terminate on their own, and handle edge cases properly.

Author: John McCardle <mccardle.john@gmail.com>

    docs: add Phase 1-3 completion summary

    - Document all completed tasks across three phases
    - Show before/after API improvements
    - Highlight technical achievements
    - Outline next steps for Phase 4-7

Author: John McCardle <mccardle.john@gmail.com>

    feat: implement mcrfpy.Timer object with pause/resume/cancel capabilities closes #103

    - Created PyTimer.h/cpp with object-oriented timer interface
    - Enhanced PyTimerCallable with pause/resume state tracking
    - Added timer control methods: pause(), resume(), cancel(), restart()
    - Added timer properties: interval, remaining, paused, active, callback
    - Fixed timing logic to prevent rapid catch-up after resume
    - Timer objects automatically register with game engine
    - Added comprehensive test demonstrating all functionality

Author: John McCardle <mccardle.john@gmail.com>

    feat(Color): add helper methods from_hex, to_hex, lerp closes #94

    - Add Color.from_hex(hex_string) class method for creating colors from hex
    - Support formats: #RRGGBB, RRGGBB, #RRGGBBAA, RRGGBBAA
    - Add color.to_hex() to convert Color to hex string
    - Add color.lerp(other, t) for smooth color interpolation
    - Comprehensive test coverage for all methods

Author: John McCardle <mccardle.john@gmail.com>

    fix: properly configure UTF-8 encoding for Python stdio

    - Use PyConfig to set stdio_encoding="UTF-8" during initialization
    - Set stdio_errors="surrogateescape" for robust handling
    - Configure in both init_python() and init_python_with_config()
    - Cleaner solution than wrapping streams after initialization
    - Fixes UnicodeEncodeError when printing unicode characters

Author: John McCardle <mccardle.john@gmail.com>

    feat(Vector): implement arithmetic operations closes #93

    - Add PyNumberMethods with add, subtract, multiply, divide, negate, absolute
    - Add rich comparison for equality/inequality checks
    - Add boolean check (zero vector is False)
    - Implement vector methods: magnitude(), normalize(), dot(), distance_to(), angle(), copy()
    - Fix UIDrawable::get_click() segfault when click_callable is null
    - Comprehensive test coverage for all arithmetic operations

Author: John McCardle <mccardle.john@gmail.com>

    feat: Complete position argument standardization for all UI classes

    - Frame and Sprite now support pos keyword override
    - Entity now accepts x,y arguments (was pos-only before)
    - All UI classes now consistently support:
      - (x, y) positional
      - ((x, y)) tuple
      - x=x, y=y keywords
      - pos=(x,y) keyword
      - pos=Vector keyword
    - Improves API consistency and flexibility

Author: John McCardle <mccardle.john@gmail.com>

    feat: Standardize position arguments across all UI classes

    - Create PyPositionHelper for consistent position parsing
    - Grid.at() now accepts (x,y), ((x,y)), x=x, y=y, pos=(x,y)
    - Caption now accepts x,y args in addition to pos
    - Grid init fully supports keyword arguments
    - Maintain backward compatibility for all formats
    - Consistent error messages across classes

Author: John McCardle <mccardle.john@gmail.com>

    feat: Add Entity.die() method for lifecycle management closes #30

    - Remove entity from its grid's entity list
    - Clear grid reference after removal
    - Safe to call multiple times (no-op if not on grid)
    - Works with shared_ptr entity management

Author: John McCardle <mccardle.john@gmail.com>

    perf: Skip out-of-bounds entities during Grid rendering closes #52

    - Add visibility bounds check in entity render loop
    - Skip entities outside view with 1 cell margin
    - Improves performance for large grids with many entities
    - Bounds check considers zoom and pan settings

Author: John McCardle <mccardle.john@gmail.com>

    verify: Sprite texture swapping functionality closes #19

    - Texture property getter/setter already implemented
    - Position/scale preservation during swap confirmed
    - Type validation for texture assignment working
    - Tests verify functionality is complete

Author: John McCardle <mccardle.john@gmail.com>

    feat: Grid size tuple support closes #90

    - Add grid_size keyword parameter to Grid.__init__
    - Accept tuple or list of two integers
    - Override grid_x/grid_y if grid_size provided
    - Maintain backward compatibility
    - Add comprehensive test coverage

Author: John McCardle <mccardle.john@gmail.com>

    feat: Phase 1 - safe constructors and _Drawable foundation

    Closes #7 - Make all UI class constructors safe:
    - Added safe default constructors for UISprite, UIGrid, UIEntity, UICaption
    - Initialize all members to predictable values
    - Made Python init functions accept no arguments
    - Added x,y properties to UIEntity

    Closes #71 - Create _Drawable Python base class:
    - Created PyDrawable.h/cpp with base type (not yet inherited by UI types)
    - Registered in module initialization

    Closes #87 - Add visible property:
    - Added bool visible=true to UIDrawable base class
    - All render methods check visibility before drawing

    Closes #88 - Add opacity property:
    - Added float opacity=1.0 to UIDrawable base class
    - UICaption and UISprite apply opacity to alpha channel

    Closes #89 - Add get_bounds() method:
    - Virtual method returns sf::FloatRect(x,y,w,h)
    - Implemented in Frame, Caption, Sprite, Grid

    Closes #98 - Add move() and resize() methods:
    - move(dx,dy) for relative movement
    - resize(w,h) for absolute sizing
    - Caption resize is no-op (size controlled by font)

Author: John McCardle <mccardle.john@gmail.com>

    docs: comprehensive alpha_streamline_2 plan and strategic vision

    - Add 7-phase development plan for alpha_streamline_2 branch
    - Define architectural dependencies and critical path
    - Identify new issues needed (Timer objects, event system, etc.)
    - Add strategic vision document with 3 transformative directions
    - Timeline: 10-12 weeks to solid Beta foundation

Author: John McCardle <mccardle.john@gmail.com>

    feat(Grid): flexible at() method arguments

    - Support tuple argument: grid.at((x, y))
    - Support keyword arguments: grid.at(x=5, y=3)
    - Support pos keyword: grid.at(pos=(2, 8))
    - Maintain backward compatibility with grid.at(x, y)
    - Add comprehensive error handling for invalid arguments

    Improves API ergonomics and Python-like flexibility
2025-07-09 22:41:15 -04:00
cd0bd5468b Squashed commit of the following: [alpha_streamline_1]
the low-hanging fruit of pre-existing issues and standardizing the
Python interfaces

Special thanks to Claude Code, ~100k output tokens for this merge

    🤖 Generated with [Claude Code](https://claude.ai/code)
    Co-Authored-By: Claude <noreply@anthropic.com>

commit 99f301e3a0
Author: John McCardle <mccardle.john@gmail.com>
Date:   Sat Jul 5 16:25:32 2025 -0400

    Add position tuple support and pos property to UI elements

    closes #83, closes #84

    - Issue #83: Add position tuple support to constructors
      - Frame and Sprite now accept both (x, y) and ((x, y)) forms
      - Also accept Vector objects as position arguments
      - Caption and Entity already supported tuple/Vector forms
      - Uses PyVector::from_arg for flexible position parsing

    - Issue #84: Add pos property to Frame and Sprite
      - Added pos getter that returns a Vector
      - Added pos setter that accepts Vector or tuple
      - Provides consistency with Caption and Entity which already had pos properties
      - All UI elements now have a uniform way to get/set positions as Vectors

    Both features improve API consistency and make it easier to work with positions.

commit 2f2b488fb5
Author: John McCardle <mccardle.john@gmail.com>
Date:   Sat Jul 5 16:18:10 2025 -0400

    Standardize sprite_index property and add scale_x/scale_y to UISprite

    closes #81, closes #82

    - Issue #81: Standardized property name to sprite_index across UISprite and UIEntity
      - Added sprite_index as the primary property name
      - Kept sprite_number as a deprecated alias for backward compatibility
      - Updated repr() methods to use sprite_index
      - Updated animation system to recognize both names

    - Issue #82: Added scale_x and scale_y properties to UISprite
      - Enables non-uniform scaling of sprites
      - scale property still works for uniform scaling
      - Both properties work with the animation system

    All existing code using sprite_number continues to work due to backward compatibility.

commit 5a003a9aa5
Author: John McCardle <mccardle.john@gmail.com>
Date:   Sat Jul 5 16:09:52 2025 -0400

    Fix multiple low priority issues

    closes #12, closes #80, closes #95, closes #96, closes #99

    - Issue #12: Set tp_new to NULL for GridPoint and GridPointState to prevent instantiation from Python
    - Issue #80: Renamed Caption.size to Caption.font_size for semantic clarity
    - Issue #95: Fixed UICollection repr to show actual derived types instead of generic UIDrawable
    - Issue #96: Added extend() method to UICollection for API consistency with UIEntityCollection
    - Issue #99: Exposed read-only properties for Texture (sprite_width, sprite_height, sheet_width, sheet_height, sprite_count, source) and Font (family, source)

    All issues have corresponding tests that verify the fixes work correctly.

commit e5affaf317
Author: John McCardle <mccardle.john@gmail.com>
Date:   Sat Jul 5 15:50:09 2025 -0400

    Fix critical issues: script loading, entity types, and color properties

    - Issue #37: Fix Windows scripts subdirectory not checked
      - Updated executeScript() to use executable_path() from platform.h
      - Scripts now load correctly when working directory differs from executable

    - Issue #76: Fix UIEntityCollection returns wrong type
      - Updated UIEntityCollectionIter::next() to check for stored Python object
      - Derived Entity classes now preserve their type when retrieved from collections

    - Issue #9: Recreate RenderTexture when resized (already fixed)
      - Confirmed RenderTexture recreation already implemented in set_size() and set_float_member()
      - Uses 1.5x padding and 4096 max size limit

    - Issue #79: Fix Color r, g, b, a properties return None
      - Implemented get_member() and set_member() in PyColor.cpp
      - Color component properties now work correctly with proper validation

    - Additional fix: Grid.at() method signature
      - Changed from METH_O to METH_VARARGS to accept two arguments

    All fixes include comprehensive tests to verify functionality.

    closes #37, closes #76, closes #9, closes #79
2025-07-05 18:56:02 -04:00