diff --git a/docs/API_REFERENCE_DYNAMIC.md b/docs/API_REFERENCE_DYNAMIC.md
index 70973d9..9c225ec 100644
--- a/docs/API_REFERENCE_DYNAMIC.md
+++ b/docs/API_REFERENCE_DYNAMIC.md
@@ -1,6 +1,6 @@
# McRogueFace API Reference
-*Generated on 2026-04-17 21:43:43*
+*Generated on 2026-04-18 07:28:57*
*This documentation was dynamically generated from the compiled module.*
diff --git a/docs/api_reference_dynamic.html b/docs/api_reference_dynamic.html
index 7e0da42..48b4abd 100644
--- a/docs/api_reference_dynamic.html
+++ b/docs/api_reference_dynamic.html
@@ -108,7 +108,7 @@
McRogueFace API Reference
-
Generated on 2026-04-17 21:43:43
+
Generated on 2026-04-18 07:28:57
This documentation was dynamically generated from the compiled module.
diff --git a/docs/mcrfpy.3 b/docs/mcrfpy.3
index 1bbffe3..a9f78ab 100644
--- a/docs/mcrfpy.3
+++ b/docs/mcrfpy.3
@@ -14,11 +14,11 @@
. ftr VB CB
. ftr VBI CBI
.\}
-.TH "MCRFPY" "3" "2026-04-17" "McRogueFace 0.2.7-prerelease-7drl2026-76-g417fc43" ""
+.TH "MCRFPY" "3" "2026-04-18" "McRogueFace 0.2.7-prerelease-7drl2026-79-g59e7221" ""
.hy
.SH McRogueFace API Reference
.PP
-\f[I]Generated on 2026-04-17 21:43:43\f[R]
+\f[I]Generated on 2026-04-18 07:28:57\f[R]
.PP
\f[I]This documentation was dynamically generated from the compiled
module.\f[R]
diff --git a/stubs/mcrfpy.pyi b/stubs/mcrfpy.pyi
index f77be4f..9852545 100644
--- a/stubs/mcrfpy.pyi
+++ b/stubs/mcrfpy.pyi
@@ -1,921 +1,2069 @@
"""Type stubs for McRogueFace Python API.
-Core game engine interface for creating roguelike games with Python.
+Auto-generated by tools/generate_stubs_v2.py via runtime introspection.
+Do not edit by hand -- regenerate after API changes:
+
+ make && ./tools/generate_all_docs.sh
"""
-from typing import Any, List, Dict, Tuple, Optional, Callable, Union, overload
+from enum import IntEnum
+from typing import Any, Callable, Dict, List, Optional, Tuple, Union, overload
-# Type aliases
-UIElement = Union['Frame', 'Caption', 'Sprite', 'Grid', 'Line', 'Circle', 'Arc']
-Transition = Union[str, None]
+# --- Enums --------------------------------------------------------------
+class Alignment(IntEnum):
+ """Alignment enum for positioning UI elements relative to parent bounds."""
+ BOTTOM_CENTER: int
+ BOTTOM_LEFT: int
+ BOTTOM_RIGHT: int
+ CENTER: int
+ CENTER_LEFT: int
+ CENTER_RIGHT: int
+ TOP_CENTER: int
+ TOP_LEFT: int
+ TOP_RIGHT: int
-# Classes
+class Behavior(IntEnum):
+ """Enum representing entity behavior types for grid.step() turn management."""
+ CUSTOM: int
+ FLEE: int
+ IDLE: int
+ LOOP: int
+ NOISE4: int
+ NOISE8: int
+ PATH: int
+ PATROL: int
+ SEEK: int
+ SLEEP: int
+ WAYPOINT: int
-class Color:
- """SFML Color Object for RGBA colors."""
-
- r: int
- g: int
- b: int
- a: int
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, r: int, g: int, b: int, a: int = 255) -> None: ...
-
- def from_hex(self, hex_string: str) -> 'Color':
- """Create color from hex string (e.g., '#FF0000' or 'FF0000')."""
- ...
-
- def to_hex(self) -> str:
- """Convert color to hex string format."""
- ...
-
- def lerp(self, other: 'Color', t: float) -> 'Color':
- """Linear interpolation between two colors."""
- ...
+class Easing(IntEnum):
+ """Easing type."""
+ EASE_IN: int
+ EASE_IN_BACK: int
+ EASE_IN_BOUNCE: int
+ EASE_IN_CIRC: int
+ EASE_IN_CUBIC: int
+ EASE_IN_ELASTIC: int
+ EASE_IN_EXPO: int
+ EASE_IN_OUT: int
+ EASE_IN_OUT_BACK: int
+ EASE_IN_OUT_BOUNCE: int
+ EASE_IN_OUT_CIRC: int
+ EASE_IN_OUT_CUBIC: int
+ EASE_IN_OUT_ELASTIC: int
+ EASE_IN_OUT_EXPO: int
+ EASE_IN_OUT_QUAD: int
+ EASE_IN_OUT_QUART: int
+ EASE_IN_OUT_SINE: int
+ EASE_IN_QUAD: int
+ EASE_IN_QUART: int
+ EASE_IN_SINE: int
+ EASE_OUT: int
+ EASE_OUT_BACK: int
+ EASE_OUT_BOUNCE: int
+ EASE_OUT_CIRC: int
+ EASE_OUT_CUBIC: int
+ EASE_OUT_ELASTIC: int
+ EASE_OUT_EXPO: int
+ EASE_OUT_QUAD: int
+ EASE_OUT_QUART: int
+ EASE_OUT_SINE: int
+ LINEAR: int
+ PING_PONG: int
+ PING_PONG_EASE_IN: int
+ PING_PONG_EASE_IN_OUT: int
+ PING_PONG_EASE_OUT: int
+ PING_PONG_SMOOTH: int
-class Vector:
- """SFML Vector Object for 2D coordinates."""
-
- x: float
- y: float
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, x: float, y: float) -> None: ...
-
- def add(self, other: 'Vector') -> 'Vector': ...
- def subtract(self, other: 'Vector') -> 'Vector': ...
- def multiply(self, scalar: float) -> 'Vector': ...
- def divide(self, scalar: float) -> 'Vector': ...
- def distance(self, other: 'Vector') -> float: ...
- def normalize(self) -> 'Vector': ...
- def dot(self, other: 'Vector') -> float: ...
+class FOV(IntEnum):
+ """FOV type."""
+ BASIC: int
+ DIAMOND: int
+ PERMISSIVE_0: int
+ PERMISSIVE_1: int
+ PERMISSIVE_2: int
+ PERMISSIVE_3: int
+ PERMISSIVE_4: int
+ PERMISSIVE_5: int
+ PERMISSIVE_6: int
+ PERMISSIVE_7: int
+ PERMISSIVE_8: int
+ RESTRICTIVE: int
+ SHADOW: int
+ SYMMETRIC_SHADOWCAST: int
-class Texture:
- """SFML Texture Object for images."""
-
- def __init__(self, filename: str) -> None: ...
-
- filename: str
- width: int
- height: int
- sprite_count: int
+class InputState(IntEnum):
+ """Enum representing input event states (pressed/released)."""
+ PRESSED: int
+ RELEASED: int
-class Font:
- """SFML Font Object for text rendering."""
-
- def __init__(self, filename: str) -> None: ...
-
- filename: str
- family: str
+class Key(IntEnum):
+ """Enum representing keyboard keys."""
+ A: int
+ ADD: int
+ APOSTROPHE: int
+ B: int
+ BACKSLASH: int
+ BACKSPACE: int
+ C: int
+ COMMA: int
+ D: int
+ DELETE: int
+ DIVIDE: int
+ DOWN: int
+ E: int
+ END: int
+ ENTER: int
+ EQUAL: int
+ ESCAPE: int
+ F: int
+ F1: int
+ F10: int
+ F11: int
+ F12: int
+ F13: int
+ F14: int
+ F15: int
+ F2: int
+ F3: int
+ F4: int
+ F5: int
+ F6: int
+ F7: int
+ F8: int
+ F9: int
+ G: int
+ GRAVE: int
+ H: int
+ HOME: int
+ HYPHEN: int
+ I: int
+ INSERT: int
+ J: int
+ K: int
+ L: int
+ LEFT: int
+ LEFT_ALT: int
+ LEFT_BRACKET: int
+ LEFT_CONTROL: int
+ LEFT_SHIFT: int
+ LEFT_SYSTEM: int
+ M: int
+ MENU: int
+ MULTIPLY: int
+ N: int
+ NUMPAD_0: int
+ NUMPAD_1: int
+ NUMPAD_2: int
+ NUMPAD_3: int
+ NUMPAD_4: int
+ NUMPAD_5: int
+ NUMPAD_6: int
+ NUMPAD_7: int
+ NUMPAD_8: int
+ NUMPAD_9: int
+ NUM_0: int
+ NUM_1: int
+ NUM_2: int
+ NUM_3: int
+ NUM_4: int
+ NUM_5: int
+ NUM_6: int
+ NUM_7: int
+ NUM_8: int
+ NUM_9: int
+ O: int
+ P: int
+ PAGE_DOWN: int
+ PAGE_UP: int
+ PAUSE: int
+ PERIOD: int
+ Q: int
+ R: int
+ RIGHT: int
+ RIGHT_ALT: int
+ RIGHT_BRACKET: int
+ RIGHT_CONTROL: int
+ RIGHT_SHIFT: int
+ RIGHT_SYSTEM: int
+ S: int
+ SEMICOLON: int
+ SLASH: int
+ SPACE: int
+ SUBTRACT: int
+ T: int
+ TAB: int
+ U: int
+ UNKNOWN: int
+ UP: int
+ V: int
+ W: int
+ X: int
+ Y: int
+ Z: int
-class Drawable:
- """Base class for all drawable UI elements."""
-
- x: float
- y: float
- visible: bool
- z_index: int
- name: str
- pos: Vector
-
- # Mouse event callbacks (#140, #141)
- on_click: Optional[Callable[[float, float, int, str], None]]
- on_enter: Optional[Callable[[float, float, int, str], None]]
- on_exit: Optional[Callable[[float, float, int, str], None]]
- on_move: Optional[Callable[[float, float, int, str], None]]
-
- # Read-only hover state (#140)
- hovered: bool
-
- def get_bounds(self) -> Tuple[float, float, float, float]:
- """Get bounding box as (x, y, width, height)."""
- ...
-
- def move(self, dx: float, dy: float) -> None:
- """Move by relative offset (dx, dy)."""
- ...
-
- def resize(self, width: float, height: float) -> None:
- """Resize to new dimensions (width, height)."""
- ...
-
-class Frame(Drawable):
- """Frame(x=0, y=0, w=0, h=0, fill_color=None, outline_color=None, outline=0, on_click=None, children=None)
-
- A rectangular frame UI element that can contain other drawable elements.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, x: float = 0, y: float = 0, w: float = 0, h: float = 0,
- fill_color: Optional[Color] = None, outline_color: Optional[Color] = None,
- outline: float = 0, on_click: Optional[Callable] = None,
- children: Optional[List[UIElement]] = None) -> None: ...
-
- w: float
- h: float
- fill_color: Color
- outline_color: Color
- outline: float
- on_click: Optional[Callable[[float, float, int], None]]
- children: 'UICollection'
- clip_children: bool
-
-class Caption(Drawable):
- """Caption(text='', x=0, y=0, font=None, fill_color=None, outline_color=None, outline=0, on_click=None)
-
- A text display UI element with customizable font and styling.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, text: str = '', x: float = 0, y: float = 0,
- font: Optional[Font] = None, fill_color: Optional[Color] = None,
- outline_color: Optional[Color] = None, outline: float = 0,
- on_click: Optional[Callable] = None) -> None: ...
-
- text: str
- font: Font
- fill_color: Color
- outline_color: Color
- outline: float
- on_click: Optional[Callable[[float, float, int], None]]
- w: float # Read-only, computed from text
- h: float # Read-only, computed from text
-
-class Sprite(Drawable):
- """Sprite(x=0, y=0, texture=None, sprite_index=0, scale=1.0, on_click=None)
-
- A sprite UI element that displays a texture or portion of a texture atlas.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, x: float = 0, y: float = 0, texture: Optional[Texture] = None,
- sprite_index: int = 0, scale: float = 1.0,
- on_click: Optional[Callable] = None) -> None: ...
-
- texture: Texture
- sprite_index: int
- scale: float
- on_click: Optional[Callable[[float, float, int], None]]
- w: float # Read-only, computed from texture
- h: float # Read-only, computed from texture
-
-class Grid(Drawable):
- """Grid(pos=(0,0), size=(0,0), grid_size=(2,2), texture=None, ...)
-
- A grid-based tilemap UI element for rendering tile-based levels and game worlds.
- Supports layers, FOV, pathfinding, and entity management.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, pos: Tuple[float, float] = (0, 0),
- size: Tuple[float, float] = (0, 0),
- grid_size: Tuple[int, int] = (2, 2),
- texture: Optional[Texture] = None,
- fill_color: Optional[Color] = None,
- on_click: Optional[Callable] = None,
- center_x: float = 0, center_y: float = 0, zoom: float = 1.0,
- visible: bool = True, opacity: float = 1.0,
- z_index: int = 0, name: str = '') -> None: ...
-
- # Dimensions
- grid_size: Tuple[int, int] # Read-only (grid_w, grid_h)
- grid_w: int # Read-only
- grid_h: int # Read-only
-
- # Position and size
- position: Tuple[float, float]
- size: Vector
- w: float
- h: float
-
- # Camera/viewport
- center: Vector # Viewport center point (pan position)
- center_x: float
- center_y: float
- zoom: float # Scale factor for rendering
-
- # Collections
- entities: 'EntityCollection' # Entities on this grid
- children: 'UICollection' # UI overlays (speech bubbles, effects)
- layers: List[Union['ColorLayer', 'TileLayer']] # Grid layers sorted by z_index
-
- # Appearance
- texture: Texture # Read-only
- fill_color: Color # Background fill color
-
- # Perspective/FOV
- perspective: Optional['Entity'] # Entity for FOV rendering (None = omniscient)
- perspective_enabled: bool # Whether to use perspective-based FOV
- fov: 'FOV' # FOV algorithm enum
- fov_radius: int # Default FOV radius
-
- # Cell-level mouse events
- on_cell_enter: Optional[Callable[['Vector'], None]]
- on_cell_exit: Optional[Callable[['Vector'], None]]
- on_cell_click: Optional[Callable[['Vector'], None]]
- hovered_cell: Optional[Tuple[int, int]] # Read-only
-
- def at(self, x: int, y: int) -> 'GridPoint':
- """Get grid point at tile coordinates."""
- ...
-
- def center_camera(self, pos: Optional[Tuple[float, float]] = None) -> None:
- """Center the camera on a tile coordinate."""
- ...
-
- # FOV methods
- def compute_fov(self, pos: Tuple[int, int], radius: int = 0,
- light_walls: bool = True, algorithm: Optional['FOV'] = None) -> None:
- """Compute field of view from a position."""
- ...
-
- def is_in_fov(self, pos: Tuple[int, int]) -> bool:
- """Check if a cell is in the field of view."""
- ...
-
- # Pathfinding methods
- def find_path(self, start: Union[Tuple[int, int], 'Vector', 'Entity'],
- end: Union[Tuple[int, int], 'Vector', 'Entity'],
- diagonal_cost: float = 1.41) -> Optional['AStarPath']:
- """Compute A* path between two points."""
- ...
-
- def get_dijkstra_map(self, root: Union[Tuple[int, int], 'Vector', 'Entity'],
- diagonal_cost: float = 1.41) -> 'DijkstraMap':
- """Get or create a Dijkstra distance map for a root position."""
- ...
-
- def clear_dijkstra_maps(self) -> None:
- """Clear all cached Dijkstra maps."""
- ...
-
- # Layer methods
- def add_layer(self, type: str, z_index: int = -1,
- texture: Optional[Texture] = None) -> Union['ColorLayer', 'TileLayer']:
- """Add a new layer to the grid."""
- ...
-
- def remove_layer(self, layer: Union['ColorLayer', 'TileLayer']) -> None:
- """Remove a layer from the grid."""
- ...
-
- def layer(self, z_index: int) -> Optional[Union['ColorLayer', 'TileLayer']]:
- """Get layer by z_index."""
- ...
-
- # Spatial queries
- def entities_in_radius(self, pos: Union[Tuple[float, float], 'Vector'],
- radius: float) -> List['Entity']:
- """Query entities within radius using spatial hash."""
- ...
-
- # HeightMap application
- def apply_threshold(self, source: 'HeightMap', range: Tuple[float, float],
- walkable: Optional[bool] = None,
- transparent: Optional[bool] = None) -> 'Grid':
- """Apply walkable/transparent properties where heightmap values are in range."""
- ...
-
- def apply_ranges(self, source: 'HeightMap',
- ranges: List[Tuple[Tuple[float, float], Dict[str, bool]]]) -> 'Grid':
- """Apply multiple thresholds in a single pass."""
- ...
-
-class Line(Drawable):
- """Line(start=None, end=None, thickness=1.0, color=None, on_click=None, **kwargs)
-
- A line UI element for drawing straight lines between two points.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, start: Optional[Tuple[float, float]] = None,
- end: Optional[Tuple[float, float]] = None,
- thickness: float = 1.0, color: Optional[Color] = None,
- on_click: Optional[Callable] = None) -> None: ...
-
- start: Vector
- end: Vector
- thickness: float
- color: Color
- on_click: Optional[Callable[[float, float, int], None]]
-
-class Circle(Drawable):
- """Circle(radius=0, center=None, fill_color=None, outline_color=None, outline=0, on_click=None, **kwargs)
-
- A circle UI element for drawing filled or outlined circles.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, radius: float = 0, center: Optional[Tuple[float, float]] = None,
- fill_color: Optional[Color] = None, outline_color: Optional[Color] = None,
- outline: float = 0, on_click: Optional[Callable] = None) -> None: ...
-
- radius: float
- center: Vector
- fill_color: Color
- outline_color: Color
- outline: float
- on_click: Optional[Callable[[float, float, int], None]]
-
-class Arc(Drawable):
- """Arc(center=None, radius=0, start_angle=0, end_angle=90, color=None, thickness=1, on_click=None, **kwargs)
-
- An arc UI element for drawing curved line segments.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, center: Optional[Tuple[float, float]] = None, radius: float = 0,
- start_angle: float = 0, end_angle: float = 90,
- color: Optional[Color] = None, thickness: float = 1.0,
- on_click: Optional[Callable] = None) -> None: ...
-
- center: Vector
- radius: float
- start_angle: float
- end_angle: float
- color: Color
- thickness: float
- on_click: Optional[Callable[[float, float, int], None]]
-
-class GridPoint:
- """Grid point representing a single tile's properties.
-
- Accessed via Grid.at(x, y). Controls walkability and transparency
- for pathfinding and FOV calculations.
- """
-
- walkable: bool # Whether entities can walk through this cell
- transparent: bool # Whether light/sight passes through this cell
- entities: List['Entity'] # Read-only list of entities at this cell
- grid_pos: Tuple[int, int] # Read-only (x, y) position in grid
+class MouseButton(IntEnum):
+ """Enum representing mouse buttons and scroll wheel."""
+ LEFT: int
+ MIDDLE: int
+ RIGHT: int
+ SCROLL_DOWN: int
+ SCROLL_UP: int
+ X1: int
+ X2: int
class Perspective(IntEnum):
- """An entity's knowledge state for a grid cell (#294).
+ """Enum representing an entity's knowledge of a cell."""
+ DISCOVERED: int
+ UNKNOWN: int
+ VISIBLE: int
- Values of entity.perspective_map. Satisfies the invariant visible is a
- subset of discovered: VISIBLE cells are always at least DISCOVERED.
- """
+class Transition(IntEnum):
+ """Transition type."""
+ FADE: int
+ NONE: int
+ SLIDE_DOWN: int
+ SLIDE_LEFT: int
+ SLIDE_RIGHT: int
+ SLIDE_UP: int
- UNKNOWN = 0 # Never seen
- DISCOVERED = 1 # Seen before, not currently visible
- VISIBLE = 2 # In current FOV
+class Traversal(IntEnum):
+ """Traversal type."""
+ INVERTED_LEVEL_ORDER: int
+ IN_ORDER: int
+ LEVEL_ORDER: int
+ POST_ORDER: int
+ PRE_ORDER: int
-class ColorLayer:
- """A color overlay layer for Grid.
-
- Provides per-cell color values for tinting, fog of war, etc.
- """
-
- z_index: int
- grid: 'Grid' # Read-only parent grid
-
- def fill(self, color: Color) -> None:
- """Fill entire layer with a single color."""
- ...
-
- def set_color(self, pos: Tuple[int, int], color: Color) -> None:
- """Set color at a specific cell."""
- ...
-
- def get_color(self, pos: Tuple[int, int]) -> Color:
- """Get color at a specific cell."""
- ...
-
-class TileLayer:
- """A tile sprite layer for Grid.
-
- Provides per-cell tile indices for multi-layer tile rendering.
- """
-
- z_index: int
- grid: 'Grid' # Read-only parent grid
- texture: Optional[Texture]
-
- def fill(self, tile_index: int) -> None:
- """Fill entire layer with a single tile index."""
- ...
-
- def set_tile(self, pos: Tuple[int, int], tile_index: int) -> None:
- """Set tile index at a specific cell."""
- ...
-
- def get_tile(self, pos: Tuple[int, int]) -> int:
- """Get tile index at a specific cell."""
- ...
-
-class FOV:
- """Field of view algorithm enum.
-
- Available algorithms:
- - FOV.BASIC: Simple raycasting
- - FOV.DIAMOND: Diamond-shaped FOV
- - FOV.SHADOW: Shadow casting (recommended)
- - FOV.PERMISSIVE_0 through FOV.PERMISSIVE_8: Permissive algorithms
- - FOV.RESTRICTIVE: Restrictive precise angle shadowcasting
- """
-
- BASIC: 'FOV'
- DIAMOND: 'FOV'
- SHADOW: 'FOV'
- PERMISSIVE_0: 'FOV'
- PERMISSIVE_1: 'FOV'
- PERMISSIVE_2: 'FOV'
- PERMISSIVE_3: 'FOV'
- PERMISSIVE_4: 'FOV'
- PERMISSIVE_5: 'FOV'
- PERMISSIVE_6: 'FOV'
- PERMISSIVE_7: 'FOV'
- PERMISSIVE_8: 'FOV'
- RESTRICTIVE: 'FOV'
+class Trigger(IntEnum):
+ """Enum representing trigger types passed to entity step() callbacks."""
+ BLOCKED: int
+ DONE: int
+ TARGET: int
+# --- Classes ------------------------------------------------------------
class AStarPath:
- """A* pathfinding result.
-
- Returned by Grid.find_path(). Can be iterated or walked step-by-step.
- """
-
- def __iter__(self) -> Any: ...
- def __len__(self) -> int: ...
-
- def walk(self) -> Optional[Tuple[int, int]]:
- """Get next step in path, or None if complete."""
+ """A computed A* path result, consumed step by step."""
+ def __init__(self, *args, **kwargs) -> None: ...
+ destination: Vector # Ending position of the path (Vector, read-only).
+ origin: Vector # Starting position of the path (Vector, read-only).
+ remaining: int # Number of steps remaining in the path (int, read-only).
+ def peek(self) -> Vector:
+ """See next step without consuming it."""
...
-
- def reverse(self) -> 'AStarPath':
- """Return a reversed copy of the path."""
- ...
-
-class DijkstraMap:
- """Dijkstra distance map for pathfinding.
-
- Created by Grid.get_dijkstra_map(). Provides distance queries
- and path finding from the root position.
- """
-
- root: Tuple[int, int] # Read-only root position
-
- def get_distance(self, pos: Tuple[int, int]) -> float:
- """Get distance from root to position (-1 if unreachable)."""
- ...
-
- def get_path(self, pos: Tuple[int, int]) -> Optional[List[Tuple[int, int]]]:
- """Get path from position to root."""
- ...
-
-class HeightMap:
- """2D height field for terrain generation.
-
- Used for procedural generation and applying terrain to grids.
- """
-
- width: int # Read-only
- height: int # Read-only
-
- def __init__(self, width: int, height: int) -> None: ...
-
- def get(self, x: int, y: int) -> float:
- """Get height value at position."""
- ...
-
- def set(self, x: int, y: int, value: float) -> None:
- """Set height value at position."""
- ...
-
- def fill(self, value: float) -> 'HeightMap':
- """Fill entire heightmap with a value."""
- ...
-
- def clear(self) -> 'HeightMap':
- """Clear heightmap to 0."""
- ...
-
- def normalize(self, min_val: float = 0.0, max_val: float = 1.0) -> 'HeightMap':
- """Normalize values to range."""
- ...
-
- def add_hill(self, center: Tuple[float, float], radius: float, height: float) -> 'HeightMap':
- """Add a hill at position."""
- ...
-
- def add_fbm(self, noise: 'NoiseSource', mulx: float = 1.0, muly: float = 1.0,
- addx: float = 0.0, addy: float = 0.0, octaves: int = 4,
- delta: float = 1.0, scale: float = 1.0) -> 'HeightMap':
- """Add fractal Brownian motion noise."""
- ...
-
- def scale(self, factor: float) -> 'HeightMap':
- """Scale all values by factor."""
- ...
-
- def clamp(self, min_val: float, max_val: float) -> 'HeightMap':
- """Clamp values to range."""
- ...
-
-class NoiseSource:
- """Coherent noise generator for procedural generation.
-
- Supports various noise types: PERLIN, SIMPLEX, WAVELET, etc.
- """
-
- def __init__(self, type: str = 'SIMPLEX', seed: Optional[int] = None) -> None: ...
-
- def get(self, x: float, y: float, z: float = 0.0) -> float:
- """Get noise value at position."""
- ...
-
-class BSP:
- """Binary space partitioning for dungeon generation.
-
- Recursively subdivides a rectangle into rooms.
- """
-
- x: int
- y: int
- width: int
- height: int
- level: int
- horizontal: bool
- position: int
-
- def __init__(self, x: int, y: int, width: int, height: int) -> None: ...
-
- def split_recursive(self, randomizer: Optional[Any] = None, nb: int = 8,
- minHSize: int = 4, minVSize: int = 4,
- maxHRatio: float = 1.5, maxVRatio: float = 1.5) -> None:
- """Recursively split the BSP tree."""
- ...
-
- def traverse(self, callback: Callable[['BSP'], bool],
- order: str = 'PRE_ORDER') -> None:
- """Traverse BSP tree calling callback for each node."""
- ...
-
- def is_leaf(self) -> bool:
- """Check if this is a leaf node (no children)."""
- ...
-
- def contains(self, x: int, y: int) -> bool:
- """Check if point is within this node's bounds."""
- ...
-
- def get_left(self) -> Optional['BSP']:
- """Get left child node."""
- ...
-
- def get_right(self) -> Optional['BSP']:
- """Get right child node."""
- ...
-
-class Entity(Drawable):
- """Entity(grid_x=0, grid_y=0, texture=None, sprite_index=0, name='')
-
- Game entity that lives within a Grid.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, grid_x: float = 0, grid_y: float = 0, texture: Optional[Texture] = None,
- sprite_index: int = 0, name: str = '') -> None: ...
-
- grid_x: float
- grid_y: float
- texture: Texture
- sprite_index: int
- grid: Optional[Grid]
- perspective_map: Optional['DiscreteMap'] # 3-state FOV memory (#294); None if no grid
-
- def at(self, x: int, y: int) -> Optional['GridPoint']:
- """Return grid.at(x, y) if the cell is currently VISIBLE to this entity
- (perspective_map[x, y] == Perspective.VISIBLE), otherwise None.
- """
- ...
-
- def die(self) -> None:
- """Remove entity from its grid."""
- ...
-
- def index(self) -> int:
- """Get index in parent grid's entity collection."""
- ...
-
-class UICollection:
- """Collection of UI drawable elements (Frame, Caption, Sprite, Grid, Line, Circle, Arc)."""
-
- def __len__(self) -> int: ...
- def __getitem__(self, index: int) -> UIElement: ...
- def __setitem__(self, index: int, value: UIElement) -> None: ...
- def __delitem__(self, index: int) -> None: ...
- def __contains__(self, item: UIElement) -> bool: ...
- def __iter__(self) -> Any: ...
- def __add__(self, other: 'UICollection') -> 'UICollection': ...
- def __iadd__(self, other: 'UICollection') -> 'UICollection': ...
-
- def append(self, item: UIElement) -> None: ...
- def extend(self, items: List[UIElement]) -> None: ...
- def remove(self, item: UIElement) -> None: ...
- def index(self, item: UIElement) -> int: ...
- def count(self, item: UIElement) -> int: ...
-
-class EntityCollection:
- """Collection of Entity objects."""
-
- def __len__(self) -> int: ...
- def __getitem__(self, index: int) -> Entity: ...
- def __setitem__(self, index: int, value: Entity) -> None: ...
- def __delitem__(self, index: int) -> None: ...
- def __contains__(self, item: Entity) -> bool: ...
- def __iter__(self) -> Any: ...
- def __add__(self, other: 'EntityCollection') -> 'EntityCollection': ...
- def __iadd__(self, other: 'EntityCollection') -> 'EntityCollection': ...
-
- def append(self, item: Entity) -> None: ...
- def extend(self, items: List[Entity]) -> None: ...
- def remove(self, item: Entity) -> None: ...
- def index(self, item: Entity) -> int: ...
- def count(self, item: Entity) -> int: ...
-
-class Scene:
- """Base class for object-oriented scenes."""
-
- name: str
- children: UICollection # #151: UI elements collection (read-only alias for get_ui())
- on_key: Optional[Callable[[str, str], None]] # Keyboard handler (key, action)
-
- def __init__(self, name: str) -> None: ...
-
- def activate(self) -> None:
- """Called when scene becomes active."""
- ...
-
- def deactivate(self) -> None:
- """Called when scene becomes inactive."""
- ...
-
- def get_ui(self) -> UICollection:
- """Get UI elements collection."""
- ...
-
- def on_keypress(self, key: str, pressed: bool) -> None:
- """Handle keyboard events (override in subclass)."""
- ...
-
- def on_click(self, x: float, y: float, button: int) -> None:
- """Handle mouse clicks (override in subclass)."""
- ...
-
- def on_enter(self) -> None:
- """Called when entering the scene (override in subclass)."""
- ...
-
- def on_exit(self) -> None:
- """Called when leaving the scene (override in subclass)."""
- ...
-
- def on_resize(self, width: int, height: int) -> None:
- """Handle window resize events (override in subclass)."""
- ...
-
- def update(self, dt: float) -> None:
- """Update scene logic (override in subclass)."""
- ...
-
-class Timer:
- """Timer object for scheduled callbacks."""
-
- name: str
- interval: int
- active: bool
-
- def __init__(self, name: str, callback: Callable[[float], None], interval: int) -> None: ...
-
- def pause(self) -> None:
- """Pause the timer."""
- ...
-
- def resume(self) -> None:
- """Resume the timer."""
- ...
-
- def cancel(self) -> None:
- """Cancel and remove the timer."""
- ...
-
-class Window:
- """Window singleton for managing the game window."""
-
- resolution: Tuple[int, int]
- fullscreen: bool
- vsync: bool
- title: str
- fps_limit: int
- game_resolution: Tuple[int, int]
- scaling_mode: str
-
- @staticmethod
- def get() -> 'Window':
- """Get the window singleton instance."""
+ def walk(self) -> Vector:
+ """Get and consume next step in the path."""
...
class Animation:
- """Animation object for animating UI properties."""
-
- target: Any
- property: str
- duration: float
- easing: str
- loop: bool
- on_complete: Optional[Callable]
-
- def __init__(self, target: Any, property: str, start_value: Any, end_value: Any,
- duration: float, easing: str = 'linear', loop: bool = False,
- on_complete: Optional[Callable] = None) -> None: ...
-
- def start(self) -> None:
- """Start the animation."""
+ """Create an animation that interpolates a property value over time."""
+ def __init__(self, property: str, target: Any, duration: float, easing: str = 'linear', delta: bool = False, loop: bool = False, callback: Callable = None) -> None: ...
+ duration: float # Animation duration in seconds (float, read-only). Total time for the animation to complete.
+ elapsed: float # Elapsed time in seconds (float, read-only). Time since the animation started.
+ is_complete: bool # Whether animation is complete (bool, read-only). True when elapsed >= duration or complete() was called.
+ is_delta: bool # Whether animation uses delta mode (bool, read-only). In delta mode, the target value is added to the starting value.
+ is_looping: bool # Whether animation loops (bool, read-only). Looping animations repeat from the start when they reach the end.
+ property: str # Target property name (str, read-only). The property being animated (e.g., 'pos', 'opacity', 'sprite_index').
+ def complete(self) -> None:
+ """Complete the animation immediately by jumping to the final value."""
...
-
- def update(self, dt: float) -> bool:
- """Update animation, returns True if still running."""
- ...
-
def get_current_value(self) -> Any:
- """Get the current interpolated value."""
+ """Get the current interpolated value of the animation."""
+ ...
+ def hasValidTarget(self) -> bool:
+ """Check if the animation still has a valid target."""
+ ...
+ def start(self, target: UIDrawable, conflict_mode: str = 'replace') -> None:
+ """Start the animation on a target UI element."""
+ ...
+ def stop(self) -> None:
+ """Stop the animation without completing it."""
+ ...
+ def update(self, delta_time: float) -> bool:
+ """Update the animation by the given time delta."""
...
-# Module functions
+class Arc:
+ """An arc UI element for drawing curved line segments."""
+ def __init__(self, center=None, radius=0, start_angle=0, end_angle=90, color=None, thickness=1, **kwargs) -> None: ...
+ align: Any # Alignment relative to parent bounds (Alignment enum or None). When set, position is automatically calculated when parent is assigned or resized. Set to None ...
+ bounds: Any # Bounding box as (pos, size) tuple of Vectors. Returns (Vector(x, y), Vector(width, height)).
+ center: Any # Center position of the arc
+ color: Any # Arc color
+ end_angle: Any # Ending angle in degrees
+ global_bounds: Any # Bounding box as (pos, size) tuple of Vectors in screen coordinates. Returns (Vector(x, y), Vector(width, height)).
+ global_position: Any # Global screen position (read-only). Calculates absolute position by walking up the parent chain.
+ grid_pos: Any # Position in grid tile coordinates (only when parent is Grid)
+ grid_size: Any # Size in grid tile coordinates (only when parent is Grid)
+ horiz_margin: float # Horizontal margin override (float, 0 = use general margin). Invalid for vertically-centered alignments (TOP_CENTER, BOTTOM_CENTER, CENTER).
+ hovered: Any # Whether mouse is currently over this element (read-only). Updated automatically by the engine during mouse movement.
+ margin: float # General margin from edge when aligned (float). Applied to both horizontal and vertical edges unless overridden. Invalid for CENTER alignment (raises ValueErr...
+ name: Any # Name for finding this element.
+ on_click: Any # Callable executed when arc is clicked. Function receives (pos: Vector, button: str, action: str).
+ on_enter: Any # Callback for mouse enter events. Called with (pos: Vector, button: str, action: str) when mouse enters this element's bounds.
+ on_exit: Any # Callback for mouse exit events. Called with (pos: Vector, button: str, action: str) when mouse leaves this element's bounds.
+ on_move: Any # Callback for mouse movement within bounds. Called with (pos: Vector, button: str, action: str) for each mouse movement while inside. Performance note: Called...
+ opacity: Any # Opacity level (0.0 = transparent, 1.0 = opaque). Automatically clamped to valid range [0.0, 1.0].
+ origin: Any # Transform origin as Vector (pivot point for rotation). Default (0,0) is top-left; set to (w/2, h/2) to rotate around center.
+ parent: Any # Parent drawable. Get: Returns the parent Frame/Grid if nested, or None if at scene level. Set: Assign a Frame/Grid to reparent, or None to remove from parent.
+ pos: Any # Position as a Vector (same as center).
+ radius: Any # Arc radius in pixels
+ rotate_with_camera: bool # Whether to rotate visually with parent Grid's camera_rotation (bool). False (default): stay screen-aligned. True: tilt with camera. Only affects children of ...
+ rotation: Any # Rotation angle in degrees (clockwise around origin). Animatable property.
+ start_angle: Any # Starting angle in degrees
+ thickness: Any # Line thickness
+ vert_margin: float # Vertical margin override (float, 0 = use general margin). Invalid for horizontally-centered alignments (CENTER_LEFT, CENTER_RIGHT, CENTER).
+ visible: bool # Whether the object is visible (bool). Invisible objects are not rendered or clickable.
+ z_index: Any # Z-order for rendering (lower values rendered first).
+ def animate(self, property: str, target: Any, duration: float, easing=None, delta=False, loop=False, callback=None, conflict_mode='replace') -> Animation:
+ """Create and start an animation on this drawable's property."""
+ ...
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def realign(self) -> None:
+ """Reapply alignment relative to parent, useful for responsive layouts."""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
-def createSoundBuffer(filename: str) -> int:
- """Load a sound effect from a file and return its buffer ID."""
+class AutoRuleSet:
+ """AutoRuleSet - LDtk auto-tile rule set for pattern-based terrain rendering."""
+ def __init__(self, *args, **kwargs) -> None: ...
+ grid_size: int # Cell size in pixels (int, read-only).
+ group_count: int # Number of rule groups (int, read-only).
+ name: str # Rule set name / layer identifier (str, read-only).
+ rule_count: int # Total number of rules across all groups (int, read-only).
+ value_count: int # Number of IntGrid terrain values (int, read-only).
+ values: Any # List of IntGrid value dicts with value and name (read-only).
+ def apply(self, discrete_map: DiscreteMap, tile_layer: TileLayer, seed: int = 0) -> None:
+ """Resolve auto-rules and write tile indices directly into a TileLayer."""
+ ...
+ def resolve(self, discrete_map: DiscreteMap, seed: int = 0) -> list[int]:
+ """Resolve IntGrid data to tile indices using LDtk auto-rules."""
+ ...
+ def terrain_enum(self) -> IntEnum:
+ """Generate a Python IntEnum from this rule set's IntGrid values."""
+ ...
+
+class BSP:
+ """Binary Space Partitioning tree for procedural dungeon generation."""
+ def __init__(self, pos: tuple[int, int], size: tuple[int, int]) -> None: ...
+ adjacency: Any # Leaf adjacency graph. adjacency[i] returns tuple of neighbor indices. Read-only.
+ bounds: Any # Root node bounds as ((x, y), (w, h)). Read-only.
+ pos: Any # Top-left position (x, y). Read-only.
+ root: Any # Reference to the root BSPNode. Read-only.
+ size: Any # Dimensions (width, height). Read-only.
+ def clear(self) -> BSP:
+ """Remove all children, keeping only the root node with original bounds. WARNING: Invalidates all existing BSPNode references from this tree."""
+ ...
+ def find(self, pos: tuple[int, int]) -> BSPNode | None:
+ """Find the smallest (deepest) node containing the position."""
+ ...
+ def get_leaf(self, index: int) -> BSPNode:
+ """Get a leaf node by its index (0 to len(bsp)-1). This is useful when working with adjacency data, which returns leaf indices."""
+ ...
+ def leaves(self) -> Iterator[BSPNode]:
+ """Iterate all leaf nodes (the actual rooms). Same as iterating the BSP directly."""
+ ...
+ def split_once(self, horizontal: bool, position: int) -> BSP:
+ """Split the root node once at the specified position. horizontal=True creates a horizontal divider, producing top/bottom rooms. horizontal=False creates a vert..."""
+ ...
+ def split_recursive(self, depth: int, min_size: tuple[int, int], max_ratio: float = 1.5, seed: int = None) -> BSP:
+ """Recursively split to the specified depth. WARNING: Invalidates all existing BSPNode references from this tree."""
+ ...
+ def to_heightmap(self, size: tuple[int, int] = None, select: str = 'leaves', shrink: int = 0, value: float = 1.0) -> HeightMap:
+ """Convert BSP node selection to a HeightMap."""
+ ...
+ def traverse(self, order: Traversal = Traversal.LEVEL_ORDER) -> Iterator[BSPNode]:
+ """Iterate all nodes in the specified order."""
+ ...
+
+class Billboard:
+ """A camera-facing 3D sprite for trees, items, particles, etc."""
+ def __init__(self, texture=None, sprite_index=0, pos=(0,0,0), scale=1.0, facing='camera_y') -> None: ...
+ facing: str # Facing mode: 'camera', 'camera_y', or 'fixed' (str)
+ opacity: float # Opacity from 0.0 (transparent) to 1.0 (opaque) (float)
+ phi: float # Vertical tilt for 'fixed' mode in radians (float)
+ pos: Any # World position as (x, y, z) tuple
+ scale: float # Uniform scale factor (float)
+ sprite_index: int # Index into sprite sheet (int)
+ texture: Any # Sprite sheet texture (Texture or None)
+ theta: float # Horizontal rotation for 'fixed' mode in radians (float)
+ visible: bool # Visibility state (bool)
+
+class CallableBinding:
+ """A binding that calls a Python function to get its value."""
+ def __init__(self, callable: Callable[[], float]) -> None: ...
+ callable: Any # The Python callable (read-only).
+ is_valid: bool # True if the callable is still valid (bool, read-only).
+ value: float # Current value from calling the callable (float, read-only). Returns None on error.
+
+class Caption:
+ """A text display UI element with customizable font and styling."""
+ def __init__(self, pos=None, font=None, text='', **kwargs) -> None: ...
+ align: Any # Alignment relative to parent bounds (Alignment enum or None). When set, position is automatically calculated when parent is assigned or resized. Set to None ...
+ bounds: Any # Bounding box as (pos, size) tuple of Vectors. Returns (Vector(x, y), Vector(width, height)).
+ fill_color: Any # Fill color of the text. Returns a copy; modifying components requires reassignment. For animation, use 'fill_color.r', 'fill_color.g', etc.
+ font_size: Any # Font size (integer) in points
+ global_bounds: Any # Bounding box as (pos, size) tuple of Vectors in screen coordinates. Returns (Vector(x, y), Vector(width, height)).
+ global_position: Any # Global screen position (read-only). Calculates absolute position by walking up the parent chain.
+ grid_pos: Any # Position in grid tile coordinates (only when parent is Grid)
+ grid_size: Any # Size in grid tile coordinates (only when parent is Grid)
+ h: Any # Text height in pixels (read-only)
+ horiz_margin: float # Horizontal margin override (float, 0 = use general margin). Invalid for vertically-centered alignments (TOP_CENTER, BOTTOM_CENTER, CENTER).
+ hovered: Any # Whether mouse is currently over this element (read-only). Updated automatically by the engine during mouse movement.
+ margin: float # General margin from edge when aligned (float). Applied to both horizontal and vertical edges unless overridden. Invalid for CENTER alignment (raises ValueErr...
+ name: Any # Name for finding elements
+ on_click: Any # Callable executed when object is clicked. Function receives (pos: Vector, button: str, action: str).
+ on_enter: Any # Callback for mouse enter events. Called with (pos: Vector, button: str, action: str) when mouse enters this element's bounds.
+ on_exit: Any # Callback for mouse exit events. Called with (pos: Vector, button: str, action: str) when mouse leaves this element's bounds.
+ on_move: Any # Callback for mouse movement within bounds. Called with (pos: Vector, button: str, action: str) for each mouse movement while inside. Performance note: Called...
+ opacity: Any # Opacity level (0.0 = transparent, 1.0 = opaque). Automatically clamped to valid range [0.0, 1.0].
+ origin: Any # Transform origin as Vector (pivot point for rotation). Default (0,0) is top-left; set to (w/2, h/2) to rotate around center.
+ outline: Any # Thickness of the border
+ outline_color: Any # Outline color of the text. Returns a copy; modifying components requires reassignment. For animation, use 'outline_color.r', 'outline_color.g', etc.
+ parent: Any # Parent drawable. Get: Returns the parent Frame/Grid if nested, or None if at scene level. Set: Assign a Frame/Grid to reparent, or None to remove from parent.
+ pos: Any # (x, y) vector
+ rotate_with_camera: bool # Whether to rotate visually with parent Grid's camera_rotation (bool). False (default): stay screen-aligned. True: tilt with camera. Only affects children of ...
+ rotation: Any # Rotation angle in degrees (clockwise around origin). Animatable property.
+ shader: Any # Shader for GPU visual effects (Shader or None). When set, the drawable is rendered through the shader program. Set to None to disable shader effects.
+ size: Any # Text dimensions as Vector (read-only)
+ text: Any # The text displayed
+ uniforms: Any # Collection of shader uniforms (read-only access to collection). Set uniforms via dict-like syntax: drawable.uniforms['name'] = value. Supports float, vec2/3/...
+ vert_margin: float # Vertical margin override (float, 0 = use general margin). Invalid for horizontally-centered alignments (CENTER_LEFT, CENTER_RIGHT, CENTER).
+ visible: bool # Whether the object is visible (bool). Invisible objects are not rendered or clickable.
+ w: Any # Text width in pixels (read-only)
+ x: Any # X coordinate of top-left corner
+ y: Any # Y coordinate of top-left corner
+ z_index: Any # Z-order for rendering (lower values rendered first). Automatically triggers scene resort when changed.
+ def animate(self, property: str, target: Any, duration: float, easing=None, delta=False, loop=False, callback=None, conflict_mode='replace') -> Animation:
+ """Create and start an animation on this drawable's property."""
+ ...
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def realign(self) -> None:
+ """Reapply alignment relative to parent, useful for responsive layouts."""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
+
+class Circle:
+ """A circle UI element for drawing filled or outlined circles."""
+ def __init__(self, radius=0, center=None, fill_color=None, outline_color=None, outline=0, **kwargs) -> None: ...
+ align: Any # Alignment relative to parent bounds (Alignment enum or None). When set, position is automatically calculated when parent is assigned or resized. Set to None ...
+ bounds: Any # Bounding box as (pos, size) tuple of Vectors. Returns (Vector(x, y), Vector(width, height)).
+ center: Any # Center position of the circle
+ fill_color: Any # Fill color of the circle
+ global_bounds: Any # Bounding box as (pos, size) tuple of Vectors in screen coordinates. Returns (Vector(x, y), Vector(width, height)).
+ global_position: Any # Global screen position (read-only). Calculates absolute position by walking up the parent chain.
+ grid_pos: Any # Position in grid tile coordinates (only when parent is Grid)
+ grid_size: Any # Size in grid tile coordinates (only when parent is Grid)
+ horiz_margin: float # Horizontal margin override (float, 0 = use general margin). Invalid for vertically-centered alignments (TOP_CENTER, BOTTOM_CENTER, CENTER).
+ hovered: Any # Whether mouse is currently over this element (read-only). Updated automatically by the engine during mouse movement.
+ margin: float # General margin from edge when aligned (float). Applied to both horizontal and vertical edges unless overridden. Invalid for CENTER alignment (raises ValueErr...
+ name: Any # Name for finding this element.
+ on_click: Any # Callable executed when circle is clicked. Function receives (pos: Vector, button: str, action: str).
+ on_enter: Any # Callback for mouse enter events. Called with (pos: Vector, button: str, action: str) when mouse enters this element's bounds.
+ on_exit: Any # Callback for mouse exit events. Called with (pos: Vector, button: str, action: str) when mouse leaves this element's bounds.
+ on_move: Any # Callback for mouse movement within bounds. Called with (pos: Vector, button: str, action: str) for each mouse movement while inside. Performance note: Called...
+ opacity: Any # Opacity level (0.0 = transparent, 1.0 = opaque). Automatically clamped to valid range [0.0, 1.0].
+ origin: Any # Transform origin as Vector (pivot point for rotation). Default (0,0) is top-left; set to (w/2, h/2) to rotate around center.
+ outline: Any # Outline thickness (0 for no outline)
+ outline_color: Any # Outline color of the circle
+ parent: Any # Parent drawable. Get: Returns the parent Frame/Grid if nested, or None if at scene level. Set: Assign a Frame/Grid to reparent, or None to remove from parent.
+ pos: Any # Position as a Vector (same as center).
+ radius: Any # Circle radius in pixels
+ rotate_with_camera: bool # Whether to rotate visually with parent Grid's camera_rotation (bool). False (default): stay screen-aligned. True: tilt with camera. Only affects children of ...
+ rotation: Any # Rotation angle in degrees (clockwise around origin). Animatable property.
+ vert_margin: float # Vertical margin override (float, 0 = use general margin). Invalid for horizontally-centered alignments (CENTER_LEFT, CENTER_RIGHT, CENTER).
+ visible: bool # Whether the object is visible (bool). Invisible objects are not rendered or clickable.
+ z_index: Any # Z-order for rendering (lower values rendered first).
+ def animate(self, property: str, target: Any, duration: float, easing=None, delta=False, loop=False, callback=None, conflict_mode='replace') -> Animation:
+ """Create and start an animation on this drawable's property."""
+ ...
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def realign(self) -> None:
+ """Reapply alignment relative to parent, useful for responsive layouts."""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
+
+class Color:
+ """RGBA color representation."""
+ def __init__(self, r: int = 0, g: int = 0, b: int = 0, a: int = 255) -> None: ...
+ a: Any # Alpha component (0-255, where 0=transparent, 255=opaque). Automatically clamped to valid range.
+ b: Any # Blue component (0-255). Automatically clamped to valid range.
+ g: Any # Green component (0-255). Automatically clamped to valid range.
+ r: Any # Red component (0-255). Automatically clamped to valid range.
+ def from_hex(self, hex_string: str) -> Color:
+ """Create a Color from a hexadecimal string."""
+ ...
+ def lerp(self, other: Color, t: float) -> Color:
+ """Linearly interpolate between this color and another."""
+ ...
+ def to_hex(self) -> str:
+ """Convert this Color to a hexadecimal string."""
+ ...
+
+class ColorLayer:
+ """A grid layer that stores RGBA colors per cell for background/overlay effects."""
+ def __init__(self, z_index=-1, name=None, grid_size=None) -> None: ...
+ grid: Any # Parent Grid or None. Setting manages layer association and handles lazy allocation.
+ grid_size: Any # Layer dimensions as (width, height) tuple.
+ name: str # Layer name (str, read-only). Used for Grid.layer(name) lookup.
+ visible: Any # Whether the layer is rendered.
+ z_index: Any # Layer z-order. Negative values render below entities.
+ def apply_gradient(self, source, range, color_low, color_high) -> ColorLayer:
+ """Interpolate between colors based on HeightMap value within range."""
+ ...
+ def apply_perspective(self, entity, visible=None, discovered=None, unknown=None) -> Any:
+ """Bind this layer to an entity for automatic FOV updates."""
+ ...
+ def apply_ranges(self, source, ranges) -> ColorLayer:
+ """Apply multiple color assignments in a single pass."""
+ ...
+ def apply_threshold(self, source, range, color) -> ColorLayer:
+ """Set fixed color for cells where HeightMap value is within range."""
+ ...
+ def at(self, pos) -> Color:
+ """at(x, y) -> Color"""
+ ...
+ def clear_perspective(self) -> Any:
+ """Remove the perspective binding from this layer."""
+ ...
+ def draw_fov(self, source, radius=None, fov=None, visible=None, discovered=None, unknown=None) -> Any:
+ """Paint cells based on field-of-view visibility from source position."""
+ ...
+ def fill(self, color) -> Any:
+ """Fill the entire layer with the specified color."""
+ ...
+ def fill_rect(self, pos, size, color) -> Any:
+ """Fill a rectangular region with a color."""
+ ...
+ def set(self, pos, color) -> Any:
+ """Set the color at cell position."""
+ ...
+ def update_perspective(self) -> Any:
+ """Redraw FOV based on the bound entity's current position."""
+ ...
+
+class DijkstraMap:
+ """A Dijkstra distance map from a fixed root position."""
+ def __init__(self, *args, **kwargs) -> None: ...
+ root: Vector # Root position that distances are measured from (Vector, read-only).
+ def distance(self, pos) -> float | None:
+ """Get distance from position to root."""
+ ...
+ def path_from(self, pos) -> AStarPath:
+ """Get full path from position to root."""
+ ...
+ def step_from(self, pos) -> Vector | None:
+ """Get single step from position toward root."""
+ ...
+ def to_heightmap(self, size=None, unreachable=-1.0) -> HeightMap:
+ """Convert distance field to a HeightMap."""
+ ...
+
+class DiscreteMap:
+ """A 2D grid of uint8 values (0-255) for discrete/categorical data."""
+ def __init__(self, size: tuple[int, int], fill: int = 0, enum: type[IntEnum] = None) -> None: ...
+ enum_type: Any # Optional IntEnum class for value interpretation.
+ size: Any # Dimensions (width, height) of the map. Read-only.
+ def add(self, other: DiscreteMap | int, *, pos=None, source_pos=None, size=None) -> DiscreteMap:
+ """Add values from another map or a scalar, with saturation to 0-255."""
+ ...
+ def bitwise_and(self, other: DiscreteMap, *, pos=None, source_pos=None, size=None) -> DiscreteMap:
+ """Bitwise AND with another DiscreteMap."""
+ ...
+ def bitwise_or(self, other: DiscreteMap, *, pos=None, source_pos=None, size=None) -> DiscreteMap:
+ """Bitwise OR with another DiscreteMap."""
+ ...
+ def bitwise_xor(self, other: DiscreteMap, *, pos=None, source_pos=None, size=None) -> DiscreteMap:
+ """Bitwise XOR with another DiscreteMap."""
+ ...
+ def bool(self, condition: int | set | callable) -> DiscreteMap:
+ """Create binary mask from condition. Returns NEW DiscreteMap."""
+ ...
+ def clear(self) -> DiscreteMap:
+ """Set all cells to 0. Equivalent to fill(0)."""
+ ...
+ def copy_from(self, other: DiscreteMap, *, pos=None, source_pos=None, size=None) -> DiscreteMap:
+ """Copy values from another DiscreteMap into the specified region."""
+ ...
+ def count(self, value: int) -> int:
+ """Count cells with the specified value."""
+ ...
+ def count_range(self, min_val: int, max_val: int) -> int:
+ """Count cells with values in the specified range (inclusive)."""
+ ...
+ def fill(self, value: int, *, pos=None, size=None) -> DiscreteMap:
+ """Set cells in region to the specified value."""
+ ...
+ def from_bytes(self, data: bytes, size: tuple[int, int], *, enum: type = None) -> DiscreteMap:
+ """Create a DiscreteMap from raw byte data."""
+ ...
+ def from_heightmap(self, hmap: HeightMap, mapping: list[tuple[tuple[float, float], int]], *, enum=None) -> DiscreteMap:
+ """Create DiscreteMap from HeightMap using range-to-value mapping."""
+ ...
+ def get(self, *args, **kwargs) -> Any:
+ """get(x, y) or (pos) -> int | Enum"""
+ ...
+ def histogram(self) -> dict[int, int]:
+ """Get a histogram of value counts."""
+ ...
+ def invert(self) -> DiscreteMap:
+ """Return NEW DiscreteMap with (255 - value) for each cell."""
+ ...
+ def mask(self) -> memoryview:
+ """Get raw uint8_t data as memoryview for libtcod compatibility."""
+ ...
+ def max(self, other: DiscreteMap, *, pos=None, source_pos=None, size=None) -> DiscreteMap:
+ """Set each cell to the maximum of this and another DiscreteMap."""
+ ...
+ def min(self, other: DiscreteMap, *, pos=None, source_pos=None, size=None) -> DiscreteMap:
+ """Set each cell to the minimum of this and another DiscreteMap."""
+ ...
+ def min_max(self) -> tuple[int, int]:
+ """Get the minimum and maximum values in the map."""
+ ...
+ def multiply(self, factor: float, *, pos=None, size=None) -> DiscreteMap:
+ """Multiply values by a scalar factor, with saturation to 0-255."""
+ ...
+ def set(self, x: int, y: int, value: int) -> None:
+ """Set the value at integer coordinates."""
+ ...
+ def subtract(self, other: DiscreteMap | int, *, pos=None, source_pos=None, size=None) -> DiscreteMap:
+ """Subtract values from another map or a scalar, with saturation to 0-255."""
+ ...
+ def to_bytes(self) -> bytes:
+ """Serialize map data to bytes (row-major, one byte per cell)."""
+ ...
+ def to_heightmap(self, mapping: dict[int, float] = None) -> HeightMap:
+ """Convert to HeightMap, optionally mapping values to floats."""
+ ...
+
+class Drawable:
+ """Base class for all drawable UI elements"""
+ def __init__(self, *args, **kwargs) -> None: ...
+ on_click: Any # Callable executed when object is clicked. Function receives (pos: Vector, button: str, action: str).
+ opacity: Any # Opacity level (0.0 = transparent, 1.0 = opaque). Automatically clamped to valid range [0.0, 1.0].
+ visible: bool # Whether the object is visible (bool). Invisible objects are not rendered or clickable.
+ z_index: Any # Z-order for rendering (lower values rendered first). Automatically triggers scene resort when changed.
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
+
+class Entity:
+ """A game entity that exists on a grid with sprite rendering."""
+ def __init__(self, grid_pos=None, texture=None, sprite_index=0, **kwargs) -> None: ...
+ behavior_type: int # Current behavior type (int, read-only). Use set_behavior() to change.
+ cell_pos: Vector # Integer logical cell position (Vector). Decoupled from draw_pos. Determines which cell this entity logically occupies for collision, pathfinding, etc.
+ cell_x: Any # Integer X cell coordinate.
+ cell_y: Any # Integer Y cell coordinate.
+ default_behavior: int # Default behavior type (int, maps to Behavior enum). Entity reverts to this after DONE trigger. Default: 0 (IDLE).
+ draw_pos: Vector # Fractional tile position for rendering (Vector). Use for smooth animation between grid cells.
+ grid: Any # Grid this entity belongs to. Get: Returns the Grid or None. Set: Assign a Grid to move entity, or None to remove from grid.
+ grid_pos: Vector # Grid position as integer cell coordinates (Vector). Alias for cell_pos.
+ grid_x: Any # Grid X position as integer cell coordinate. Alias for cell_x.
+ grid_y: Any # Grid Y position as integer cell coordinate. Alias for cell_y.
+ labels: frozenset # Set of string labels for collision/targeting (frozenset). Assign any iterable of strings to replace all labels.
+ move_speed: float # Animation duration for behavior movement in seconds (float). 0 = instant. Default: 0.15.
+ name: Any # Name for finding elements
+ opacity: Any # Opacity (0.0 = transparent, 1.0 = opaque)
+ perspective_map: DiscreteMap # Per-entity FOV memory (DiscreteMap, read-write). 3-state values per cell: 0 = unknown (never seen), 1 = discovered (seen before, not currently visible), 2 = ...
+ pos: Vector # Pixel position relative to grid (Vector). Computed as draw_pos * tile_size. Requires entity to be attached to a grid.
+ shader: Any # Shader for GPU visual effects (Shader or None). When set, the entity is rendered through the shader program. Set to None to disable shader effects.
+ sight_radius: int # FOV radius for TARGET trigger (int). Default: 10.
+ sprite_grid: Any # Per-tile sprite indices for composite multi-tile entities (list of lists or None). Row-major, dimensions must match tile_width x tile_height. Use -1 for empt...
+ sprite_index: Any # Sprite index on the texture on the display
+ sprite_offset: Vector # Pixel offset for oversized sprites (Vector). Applied pre-zoom during grid rendering.
+ sprite_offset_x: Any # X component of sprite pixel offset.
+ sprite_offset_y: Any # Y component of sprite pixel offset.
+ step: Any # Step callback for grid.step() turn management. Called with (trigger, data) when behavior triggers fire. Set to None to clear.
+ target_label: Any # Label to search for with TARGET trigger (str or None). Default: None.
+ tile_height: int # Entity height in tiles (int). Must be >= 1. Default 1.
+ tile_size: Any # Entity size in tiles as (width, height) Vector. Default (1, 1).
+ tile_width: int # Entity width in tiles (int). Must be >= 1. Default 1.
+ turn_order: int # Turn order for grid.step() (int). 0 = skip, higher values go later. Default: 1.
+ uniforms: Any # Collection of shader uniforms (read-only access to collection). Set uniforms via dict-like syntax: entity.uniforms['name'] = value. Supports float, vec2/3/4 ...
+ visible: Any # Visibility flag
+ x: Any # Pixel X position relative to grid. Requires entity to be attached to a grid.
+ y: Any # Pixel Y position relative to grid. Requires entity to be attached to a grid.
+ def add_label(self, label: str) -> None:
+ """Add a label to this entity. Idempotent (adding same label twice is safe)."""
+ ...
+ def animate(self, property: str, target: Any, duration: float, easing=None, delta=False, loop=False, callback=None, conflict_mode='replace') -> Animation:
+ """Create and start an animation on this entity's property."""
+ ...
+ def at(self, *args, **kwargs) -> Any:
+ """at(x, y) or at(pos) -> GridPoint | None"""
+ ...
+ def die(self, *args, **kwargs) -> Any:
+ """Remove this entity from its grid."""
+ ...
+ def find_path(self, target, diagonal_cost=1.41, collide=None) -> AStarPath | None:
+ """Find a path from this entity to the target position."""
+ ...
+ def has_label(self, label: str) -> bool:
+ """Check if this entity has the given label."""
+ ...
+ def index(self, *args, **kwargs) -> Any:
+ """Return the index of this entity in its grid's entity collection"""
+ ...
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def path_to(self, *args, **kwargs) -> Any:
+ """path_to(x, y) or path_to(target) -> list"""
+ ...
+ def remove_label(self, label: str) -> None:
+ """Remove a label from this entity. No-op if label not present."""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
+ def set_behavior(self, type, waypoints=None, turns=0, path=None) -> None:
+ """Configure this entity's behavior for grid.step() turn management."""
+ ...
+ def update_visibility(self) -> None:
+ """Update entity's visibility state based on current FOV."""
+ ...
+ def visible_entities(self, fov=None, radius=None) -> list[Entity]:
+ """Get list of other entities visible from this entity's position."""
+ ...
+
+class Entity3D:
+ """A 3D game entity that exists on a Viewport3D's navigation grid."""
+ def __init__(self, pos=None, **kwargs) -> None: ...
+ anim_clip: Any # Current animation clip name. Set to play an animation.
+ anim_frame: Any # Current animation frame number (read-only, approximate at 30fps).
+ anim_loop: Any # Whether animation loops when it reaches the end.
+ anim_paused: Any # Whether animation playback is paused.
+ anim_speed: Any # Animation playback speed multiplier. 1.0 = normal speed.
+ anim_time: Any # Current time position in animation (seconds).
+ auto_animate: Any # Enable auto-play of walk/idle clips based on movement.
+ color: Any # Entity render color.
+ grid_pos: Any # Grid position (x, z). Same as pos.
+ idle_clip: Any # Animation clip to play when entity is stationary.
+ is_moving: Any # Whether entity is currently moving (read-only).
+ model: Model3D # 3D model (Model3D). If None, uses placeholder cube.
+ name: str # Entity name (str). Used for find() lookup.
+ on_anim_complete: Any # Callback(entity, clip_name) when non-looping animation ends.
+ pos: Any # Grid position (x, z). Setting triggers smooth movement.
+ rotation: Any # Y-axis rotation in degrees.
+ scale: Any # Uniform scale factor. Can also set as (x, y, z) tuple.
+ viewport: Any # Owning Viewport3D (read-only).
+ visible: Any # Visibility state.
+ walk_clip: Any # Animation clip to play when entity is moving.
+ world_pos: Any # Current world position (x, y, z) (read-only). Includes animation interpolation.
+ def animate(self, property, target, duration, easing=None, delta=False, callback=None, conflict_mode=None) -> Any:
+ """Animate a property over time."""
+ ...
+ def at(self, x, z) -> dict:
+ """Get visibility state for a cell from this entity's perspective."""
+ ...
+ def clear_path(self) -> Any:
+ """Clear the movement queue and stop at current position."""
+ ...
+ def follow_path(self, path) -> Any:
+ """Queue path positions for smooth movement."""
+ ...
+ def path_to(self, *args, **kwargs) -> Any:
+ """path_to(x, z) or path_to(pos=(x, z)) -> list"""
+ ...
+ def teleport(self, *args, **kwargs) -> Any:
+ """teleport(x, z) or teleport(pos=(x, z))"""
+ ...
+ def update_visibility(self) -> Any:
+ """Recompute field of view from current position."""
+ ...
+
+class EntityCollection3D:
+ """Collection of Entity3D objects belonging to a Viewport3D."""
+ def __init__(self, *args, **kwargs) -> None: ...
+ def append(self, entity) -> Any:
+ """Add an Entity3D to the collection."""
+ ...
+ def clear(self) -> Any:
+ """Remove all entities from the collection."""
+ ...
+ def extend(self, iterable) -> Any:
+ """Add all Entity3D objects from iterable to the collection."""
+ ...
+ def find(self, name) -> Entity3D or None:
+ """Find an Entity3D by name. Returns None if not found."""
+ ...
+ def pop(self, index=-1) -> Entity3D:
+ """Remove and return Entity3D at index (default: last)."""
+ ...
+ def remove(self, entity) -> Any:
+ """Remove an Entity3D from the collection."""
+ ...
+
+class EntityCollection3DIter:
+ """Iterator for EntityCollection3D"""
+ def __init__(self, *args, **kwargs) -> None: ...
+
+class Font:
+ """A font resource for rendering text in Caption elements."""
+ def __init__(self, filename: str) -> None: ...
+ family: str # Font family name (str, read-only). Retrieved from font metadata.
+ source: str # Source filename path (str, read-only). The path used to load this font.
+
+class Frame:
+ """A rectangular frame UI element that can contain other drawable elements."""
+ def __init__(self, pos=None, size=None, **kwargs) -> None: ...
+ align: Any # Alignment relative to parent bounds (Alignment enum or None). When set, position is automatically calculated when parent is assigned or resized. Set to None ...
+ bounds: Any # Bounding box as (pos, size) tuple of Vectors. Returns (Vector(x, y), Vector(width, height)).
+ cache_subtree: Any # #144: Cache subtree rendering to texture for performance
+ children: Any # UICollection of objects on top of this one
+ clip_children: Any # Whether to clip children to frame bounds
+ fill_color: Any # Fill color of the rectangle. Returns a copy; modifying components requires reassignment. For animation, use 'fill_color.r', 'fill_color.g', etc.
+ global_bounds: Any # Bounding box as (pos, size) tuple of Vectors in screen coordinates. Returns (Vector(x, y), Vector(width, height)).
+ global_position: Any # Global screen position (read-only). Calculates absolute position by walking up the parent chain.
+ grid_pos: Any # Position in grid tile coordinates (only when parent is Grid)
+ grid_size: Any # Size in grid tile coordinates (only when parent is Grid)
+ h: Any # height of the rectangle
+ horiz_margin: float # Horizontal margin override (float, 0 = use general margin). Invalid for vertically-centered alignments (TOP_CENTER, BOTTOM_CENTER, CENTER).
+ hovered: Any # Whether mouse is currently over this element (read-only). Updated automatically by the engine during mouse movement.
+ margin: float # General margin from edge when aligned (float). Applied to both horizontal and vertical edges unless overridden. Invalid for CENTER alignment (raises ValueErr...
+ name: Any # Name for finding elements
+ on_click: Any # Callable executed when object is clicked. Function receives (pos: Vector, button: str, action: str).
+ on_enter: Any # Callback for mouse enter events. Called with (pos: Vector, button: str, action: str) when mouse enters this element's bounds.
+ on_exit: Any # Callback for mouse exit events. Called with (pos: Vector, button: str, action: str) when mouse leaves this element's bounds.
+ on_move: Any # Callback for mouse movement within bounds. Called with (pos: Vector, button: str, action: str) for each mouse movement while inside. Performance note: Called...
+ opacity: Any # Opacity level (0.0 = transparent, 1.0 = opaque). Automatically clamped to valid range [0.0, 1.0].
+ origin: Any # Transform origin as Vector (pivot point for rotation). Default (0,0) is top-left; set to (w/2, h/2) to rotate around center.
+ outline: Any # Thickness of the border
+ outline_color: Any # Outline color of the rectangle. Returns a copy; modifying components requires reassignment. For animation, use 'outline_color.r', 'outline_color.g', etc.
+ parent: Any # Parent drawable. Get: Returns the parent Frame/Grid if nested, or None if at scene level. Set: Assign a Frame/Grid to reparent, or None to remove from parent.
+ pos: Any # Position as a Vector
+ rotate_with_camera: bool # Whether to rotate visually with parent Grid's camera_rotation (bool). False (default): stay screen-aligned. True: tilt with camera. Only affects children of ...
+ rotation: Any # Rotation angle in degrees (clockwise around origin). Animatable property.
+ shader: Any # Shader for GPU visual effects (Shader or None). When set, the drawable is rendered through the shader program. Set to None to disable shader effects.
+ uniforms: Any # Collection of shader uniforms (read-only access to collection). Set uniforms via dict-like syntax: drawable.uniforms['name'] = value. Supports float, vec2/3/...
+ vert_margin: float # Vertical margin override (float, 0 = use general margin). Invalid for horizontally-centered alignments (CENTER_LEFT, CENTER_RIGHT, CENTER).
+ visible: bool # Whether the object is visible (bool). Invisible objects are not rendered or clickable.
+ w: Any # width of the rectangle
+ x: Any # X coordinate of top-left corner
+ y: Any # Y coordinate of top-left corner
+ z_index: Any # Z-order for rendering (lower values rendered first). Automatically triggers scene resort when changed.
+ def animate(self, property: str, target: Any, duration: float, easing=None, delta=False, loop=False, callback=None, conflict_mode='replace') -> Animation:
+ """Create and start an animation on this drawable's property."""
+ ...
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def realign(self) -> None:
+ """Reapply alignment relative to parent, useful for responsive layouts."""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
+
+class Grid:
+ """A grid-based UI element for tile-based rendering and entity management."""
+ def __init__(self, grid_size=None, pos=None, size=None, texture=None, **kwargs) -> None: ...
+ align: Any # Alignment relative to parent bounds (Alignment enum or None). When set, position is automatically calculated when parent is assigned or resized. Set to None ...
+ bounds: Any # Bounding box as (pos, size) tuple of Vectors. Returns (Vector(x, y), Vector(width, height)).
+ camera_rotation: Any # Rotation of grid contents around camera center (degrees).
+ center: Any # Camera center point in pixel coordinates.
+ center_x: Any # center of the view X-coordinate
+ center_y: Any # center of the view Y-coordinate
+ children: Any # UICollection of UIDrawable children (speech bubbles, effects, overlays)
+ entities: Any # EntityCollection of entities on this grid
+ fill_color: Any # Background fill color.
+ fov: Any # FOV algorithm for this grid (mcrfpy.FOV enum). Used by entity.updateVisibility() and layer methods when fov=None.
+ fov_radius: Any # Default FOV radius for this grid. Used when radius not specified.
+ global_bounds: Any # Bounding box as (pos, size) tuple of Vectors in screen coordinates. Returns (Vector(x, y), Vector(width, height)).
+ global_position: Any # Global screen position (read-only). Calculates absolute position by walking up the parent chain.
+ grid_data: Any # The underlying grid data object (for multi-view scenarios).
+ grid_h: Any # Grid height in cells
+ grid_pos: Any # Position in parent grid's tile coordinates (only when parent is Grid)
+ grid_size: Any # Grid dimensions (grid_w, grid_h)
+ grid_w: Any # Grid width in cells
+ h: Any # visible widget height
+ horiz_margin: float # Horizontal margin override (float, 0 = use general margin). Invalid for vertically-centered alignments (TOP_CENTER, BOTTOM_CENTER, CENTER).
+ hovered: Any # Whether mouse is currently over this element (read-only). Updated automatically by the engine during mouse movement.
+ hovered_cell: Any # Currently hovered cell as (x, y) tuple, or None if not hovering.
+ layers: ColorLayer # List of grid layers (ColorLayer, TileLayer) sorted by z_index
+ margin: float # General margin from edge when aligned (float). Applied to both horizontal and vertical edges unless overridden. Invalid for CENTER alignment (raises ValueErr...
+ name: Any # Name for finding elements
+ on_cell_click: Any # Callback when a grid cell is clicked. Called with (cell_pos: Vector).
+ on_cell_enter: Any # Callback when mouse enters a grid cell. Called with (cell_pos: Vector).
+ on_cell_exit: Any # Callback when mouse exits a grid cell. Called with (cell_pos: Vector).
+ on_click: Any # Callable executed when object is clicked.
+ on_enter: Any # Callback for mouse enter events. Called with (pos: Vector, button: str, action: str) when mouse enters this element's bounds.
+ on_exit: Any # Callback for mouse exit events. Called with (pos: Vector, button: str, action: str) when mouse leaves this element's bounds.
+ on_move: Any # Callback for mouse movement within bounds. Called with (pos: Vector, button: str, action: str) for each mouse movement while inside. Performance note: Called...
+ opacity: Any # Opacity level (0.0 = transparent, 1.0 = opaque). Automatically clamped to valid range [0.0, 1.0].
+ origin: Any # Transform origin as Vector (pivot point for rotation). Default (0,0) is top-left; set to (w/2, h/2) to rotate around center.
+ parent: Any # Parent drawable. Get: Returns the parent Frame/Grid if nested, or None if at scene level. Set: Assign a Frame/Grid to reparent, or None to remove from parent.
+ perspective: Any # Entity whose perspective to use for FOV rendering (None for omniscient view). Setting an entity automatically enables perspective mode.
+ perspective_enabled: Any # Whether to use perspective-based FOV rendering. When True with no valid entity, all cells appear undiscovered.
+ pos: Any # Position of the grid as Vector
+ rotate_with_camera: bool # Whether to rotate visually with parent Grid's camera_rotation (bool). False (default): stay screen-aligned. True: tilt with camera. Only affects children of ...
+ rotation: Any # Rotation angle in degrees (clockwise around origin). Animatable property.
+ shader: Any # Shader for GPU visual effects (Shader or None). When set, the drawable is rendered through the shader program. Set to None to disable shader effects.
+ size: Any # Size of the grid as Vector (width, height)
+ texture: Any # Texture used for tile rendering (read-only).
+ uniforms: Any # Collection of shader uniforms (read-only access to collection). Set uniforms via dict-like syntax: drawable.uniforms['name'] = value. Supports float, vec2/3/...
+ vert_margin: float # Vertical margin override (float, 0 = use general margin). Invalid for horizontally-centered alignments (CENTER_LEFT, CENTER_RIGHT, CENTER).
+ view: Any # Auto-created GridView for rendering (read-only). When Grid is appended to a scene, this view is what actually renders.
+ visible: bool # Whether the object is visible (bool). Invisible objects are not rendered or clickable.
+ w: Any # visible widget width
+ x: Any # top-left corner X-coordinate
+ y: Any # top-left corner Y-coordinate
+ z_index: Any # Z-order for rendering (lower values rendered first).
+ zoom: Any # Zoom level for rendering.
+ def add_layer(self, layer: ColorLayer | TileLayer) -> ColorLayer | TileLayer:
+ """Add a layer to the grid."""
+ ...
+ def animate(self, property: str, target: Any, duration: float, easing=None, delta=False, loop=False, callback=None, conflict_mode='replace') -> Animation:
+ """Create and start an animation on this drawable's property."""
+ ...
+ def apply_ranges(self, source: HeightMap, ranges: list) -> Grid:
+ """Apply multiple thresholds in a single pass."""
+ ...
+ def apply_threshold(self, source: HeightMap, range: tuple, walkable: bool = None, transparent: bool = None) -> Grid:
+ """Apply walkable/transparent properties where heightmap values are in range."""
+ ...
+ def at(self, *args, **kwargs) -> Any: ...
+ def center_camera(self, pos: tuple = None) -> None:
+ """Center the camera on a tile coordinate."""
+ ...
+ def clear_dijkstra_maps(self) -> None:
+ """Clear all cached Dijkstra maps."""
+ ...
+ def compute_fov(self, pos, radius: int = 0, light_walls: bool = True, algorithm: int = FOV_BASIC) -> None:
+ """Compute field of view from a position."""
+ ...
+ def entities_in_radius(self, pos: tuple|Vector, radius: float) -> list[Entity]:
+ """Query entities within radius using spatial hash (O(k) where k = nearby entities)."""
+ ...
+ def find_path(self, start, end, diagonal_cost=1.41, collide=None) -> AStarPath | None:
+ """Compute A* path between two points."""
+ ...
+ def get_dijkstra_map(self, root, diagonal_cost=1.41, collide=None) -> DijkstraMap:
+ """Get or create a Dijkstra distance map for a root position."""
+ ...
+ def is_in_fov(self, pos) -> bool:
+ """Check if a cell is in the field of view."""
+ ...
+ def layer(self, name: str) -> ColorLayer | TileLayer | None:
+ """Get a layer by its name."""
+ ...
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def realign(self) -> None:
+ """Reapply alignment relative to parent, useful for responsive layouts."""
+ ...
+ def remove_layer(self, name_or_layer: str | ColorLayer | TileLayer) -> None:
+ """Remove a layer from the grid."""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
+ def step(self, n=1, turn_order=None) -> None:
+ """Execute n rounds of turn-based entity behavior."""
+ ...
+
+class GridView:
+ """A grid-based UI element for tile-based rendering and entity management."""
+ def __init__(self, *args, **kwargs) -> None: ...
+ align: Any # Alignment relative to parent bounds (Alignment enum or None). When set, position is automatically calculated when parent is assigned or resized. Set to None ...
+ bounds: Any # Bounding box as (pos, size) tuple of Vectors. Returns (Vector(x, y), Vector(width, height)).
+ camera_rotation: Any # Rotation of grid contents around camera center (degrees).
+ center: Any # Camera center point in pixel coordinates.
+ center_x: Any # center of the view X-coordinate
+ center_y: Any # center of the view Y-coordinate
+ children: Any # UICollection of UIDrawable children (speech bubbles, effects, overlays)
+ entities: Any # EntityCollection of entities on this grid
+ fill_color: Any # Background fill color.
+ fov: Any # FOV algorithm for this grid (mcrfpy.FOV enum). Used by entity.updateVisibility() and layer methods when fov=None.
+ fov_radius: Any # Default FOV radius for this grid. Used when radius not specified.
+ global_bounds: Any # Bounding box as (pos, size) tuple of Vectors in screen coordinates. Returns (Vector(x, y), Vector(width, height)).
+ global_position: Any # Global screen position (read-only). Calculates absolute position by walking up the parent chain.
+ grid_data: Any # The underlying grid data object (for multi-view scenarios).
+ grid_h: Any # Grid height in cells
+ grid_pos: Any # Position in parent grid's tile coordinates (only when parent is Grid)
+ grid_size: Any # Grid dimensions (grid_w, grid_h)
+ grid_w: Any # Grid width in cells
+ h: Any # visible widget height
+ horiz_margin: float # Horizontal margin override (float, 0 = use general margin). Invalid for vertically-centered alignments (TOP_CENTER, BOTTOM_CENTER, CENTER).
+ hovered: Any # Whether mouse is currently over this element (read-only). Updated automatically by the engine during mouse movement.
+ hovered_cell: Any # Currently hovered cell as (x, y) tuple, or None if not hovering.
+ layers: ColorLayer # List of grid layers (ColorLayer, TileLayer) sorted by z_index
+ margin: float # General margin from edge when aligned (float). Applied to both horizontal and vertical edges unless overridden. Invalid for CENTER alignment (raises ValueErr...
+ name: Any # Name for finding elements
+ on_cell_click: Any # Callback when a grid cell is clicked. Called with (cell_pos: Vector).
+ on_cell_enter: Any # Callback when mouse enters a grid cell. Called with (cell_pos: Vector).
+ on_cell_exit: Any # Callback when mouse exits a grid cell. Called with (cell_pos: Vector).
+ on_click: Any # Callable executed when object is clicked.
+ on_enter: Any # Callback for mouse enter events. Called with (pos: Vector, button: str, action: str) when mouse enters this element's bounds.
+ on_exit: Any # Callback for mouse exit events. Called with (pos: Vector, button: str, action: str) when mouse leaves this element's bounds.
+ on_move: Any # Callback for mouse movement within bounds. Called with (pos: Vector, button: str, action: str) for each mouse movement while inside. Performance note: Called...
+ opacity: Any # Opacity level (0.0 = transparent, 1.0 = opaque). Automatically clamped to valid range [0.0, 1.0].
+ origin: Any # Transform origin as Vector (pivot point for rotation). Default (0,0) is top-left; set to (w/2, h/2) to rotate around center.
+ parent: Any # Parent drawable. Get: Returns the parent Frame/Grid if nested, or None if at scene level. Set: Assign a Frame/Grid to reparent, or None to remove from parent.
+ perspective: Any # Entity whose perspective to use for FOV rendering (None for omniscient view). Setting an entity automatically enables perspective mode.
+ perspective_enabled: Any # Whether to use perspective-based FOV rendering. When True with no valid entity, all cells appear undiscovered.
+ pos: Any # Position of the grid as Vector
+ rotate_with_camera: bool # Whether to rotate visually with parent Grid's camera_rotation (bool). False (default): stay screen-aligned. True: tilt with camera. Only affects children of ...
+ rotation: Any # Rotation angle in degrees (clockwise around origin). Animatable property.
+ shader: Any # Shader for GPU visual effects (Shader or None). When set, the drawable is rendered through the shader program. Set to None to disable shader effects.
+ size: Any # Size of the grid as Vector (width, height)
+ texture: Any # Texture used for tile rendering (read-only).
+ uniforms: Any # Collection of shader uniforms (read-only access to collection). Set uniforms via dict-like syntax: drawable.uniforms['name'] = value. Supports float, vec2/3/...
+ vert_margin: float # Vertical margin override (float, 0 = use general margin). Invalid for horizontally-centered alignments (CENTER_LEFT, CENTER_RIGHT, CENTER).
+ view: Any # Auto-created GridView for rendering (read-only). When Grid is appended to a scene, this view is what actually renders.
+ visible: bool # Whether the object is visible (bool). Invisible objects are not rendered or clickable.
+ w: Any # visible widget width
+ x: Any # top-left corner X-coordinate
+ y: Any # top-left corner Y-coordinate
+ z_index: Any # Z-order for rendering (lower values rendered first).
+ zoom: Any # Zoom level for rendering.
+ def add_layer(self, layer: ColorLayer | TileLayer) -> ColorLayer | TileLayer:
+ """Add a layer to the grid."""
+ ...
+ def animate(self, property: str, target: Any, duration: float, easing=None, delta=False, loop=False, callback=None, conflict_mode='replace') -> Animation:
+ """Create and start an animation on this drawable's property."""
+ ...
+ def apply_ranges(self, source: HeightMap, ranges: list) -> Grid:
+ """Apply multiple thresholds in a single pass."""
+ ...
+ def apply_threshold(self, source: HeightMap, range: tuple, walkable: bool = None, transparent: bool = None) -> Grid:
+ """Apply walkable/transparent properties where heightmap values are in range."""
+ ...
+ def at(self, *args, **kwargs) -> Any: ...
+ def center_camera(self, pos: tuple = None) -> None:
+ """Center the camera on a tile coordinate."""
+ ...
+ def clear_dijkstra_maps(self) -> None:
+ """Clear all cached Dijkstra maps."""
+ ...
+ def compute_fov(self, pos, radius: int = 0, light_walls: bool = True, algorithm: int = FOV_BASIC) -> None:
+ """Compute field of view from a position."""
+ ...
+ def entities_in_radius(self, pos: tuple|Vector, radius: float) -> list[Entity]:
+ """Query entities within radius using spatial hash (O(k) where k = nearby entities)."""
+ ...
+ def find_path(self, start, end, diagonal_cost=1.41, collide=None) -> AStarPath | None:
+ """Compute A* path between two points."""
+ ...
+ def get_dijkstra_map(self, root, diagonal_cost=1.41, collide=None) -> DijkstraMap:
+ """Get or create a Dijkstra distance map for a root position."""
+ ...
+ def is_in_fov(self, pos) -> bool:
+ """Check if a cell is in the field of view."""
+ ...
+ def layer(self, name: str) -> ColorLayer | TileLayer | None:
+ """Get a layer by its name."""
+ ...
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def realign(self) -> None:
+ """Reapply alignment relative to parent, useful for responsive layouts."""
+ ...
+ def remove_layer(self, name_or_layer: str | ColorLayer | TileLayer) -> None:
+ """Remove a layer from the grid."""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
+ def step(self, n=1, turn_order=None) -> None:
+ """Execute n rounds of turn-based entity behavior."""
+ ...
+
+class HeightMap:
+ """A 2D grid of float values for procedural generation."""
+ def __init__(self, size: tuple[int, int], fill: float = 0.0) -> None: ...
+ size: Any # Dimensions (width, height) of the heightmap. Read-only.
+ def add(self, other: HeightMap, *, pos=None, source_pos=None, size=None) -> HeightMap:
+ """Add another heightmap's values to this one in the specified region."""
+ ...
+ def add_bsp(self, bsp: BSP, *, pos=None, select: str = 'leaves', nodes: list = None, shrink: int = 0, value: float = 1.0) -> HeightMap:
+ """Add BSP node regions to heightmap. More efficient than creating intermediate HeightMap."""
+ ...
+ def add_constant(self, value: float, *, pos=None, size=None) -> HeightMap:
+ """Add a constant value to cells in region."""
+ ...
+ def add_hill(self, center, radius: float, height: float) -> HeightMap:
+ """Add a smooth hill at the specified position."""
+ ...
+ def add_noise(self, source: NoiseSource, world_origin: tuple = (0.0, 0.0), world_size: tuple = None, mode: str = 'fbm', octaves: int = 4, scale: float = 1.0) -> HeightMap:
+ """Sample noise and add to current values. More efficient than creating intermediate HeightMap."""
+ ...
+ def add_voronoi(self, num_points: int, coefficients: tuple = (1.0, -0.5), seed: int = None) -> HeightMap:
+ """Add Voronoi-based terrain features."""
+ ...
+ def clamp(self, min: float = 0.0, max: float = 1.0, *, pos=None, size=None) -> HeightMap:
+ """Clamp values in region to the specified range."""
+ ...
+ def clear(self) -> HeightMap:
+ """Set all cells to 0.0. Equivalent to fill(0.0)."""
+ ...
+ def copy_from(self, other: HeightMap, *, pos=None, source_pos=None, size=None) -> HeightMap:
+ """Copy values from another heightmap into the specified region."""
+ ...
+ def count_in_range(self, range: tuple[float, float]) -> int:
+ """Count cells with values in the specified range (inclusive)."""
+ ...
+ def dig_bezier(self, points: tuple, start_radius: float, end_radius: float, start_height: float, end_height: float) -> HeightMap:
+ """Construct a canal along a cubic Bezier curve with specified heights."""
+ ...
+ def dig_hill(self, center, radius: float, target_height: float) -> HeightMap:
+ """Construct a pit or crater with the specified center height."""
+ ...
+ def fill(self, value: float, *, pos=None, size=None) -> HeightMap:
+ """Set cells in region to the specified value."""
+ ...
+ def get(self, *args, **kwargs) -> Any:
+ """get(x, y) or (pos) -> float"""
+ ...
+ def get_interpolated(self, *args, **kwargs) -> Any:
+ """get_interpolated(x, y) or (pos) -> float"""
+ ...
+ def get_normal(self, *args, **kwargs) -> Any:
+ """get_normal(x, y, water_level=0.0) or (pos, water_level=0.0) -> tuple[float, float, float]"""
+ ...
+ def get_slope(self, *args, **kwargs) -> Any:
+ """get_slope(x, y) or (pos) -> float"""
+ ...
+ def inverse(self) -> HeightMap:
+ """Return NEW HeightMap with (1.0 - value) for each cell."""
+ ...
+ def lerp(self, other: HeightMap, t: float, *, pos=None, source_pos=None, size=None) -> HeightMap:
+ """Linear interpolation between this and another heightmap in the specified region."""
+ ...
+ def max(self, other: HeightMap, *, pos=None, source_pos=None, size=None) -> HeightMap:
+ """Set each cell in region to the maximum of this and another heightmap."""
+ ...
+ def mid_point_displacement(self, roughness: float = 0.5, seed: int = None) -> HeightMap:
+ """Generate terrain using midpoint displacement algorithm (diamond-square)."""
+ ...
+ def min(self, other: HeightMap, *, pos=None, source_pos=None, size=None) -> HeightMap:
+ """Set each cell in region to the minimum of this and another heightmap."""
+ ...
+ def min_max(self) -> tuple[float, float]:
+ """Get the minimum and maximum height values in the map."""
+ ...
+ def multiply(self, other: HeightMap, *, pos=None, source_pos=None, size=None) -> HeightMap:
+ """Multiply this heightmap by another in the specified region (useful for masking)."""
+ ...
+ def multiply_bsp(self, bsp: BSP, *, pos=None, select: str = 'leaves', nodes: list = None, shrink: int = 0, value: float = 1.0) -> HeightMap:
+ """Multiply by BSP regions. Effectively masks the heightmap to node interiors."""
+ ...
+ def multiply_noise(self, source: NoiseSource, world_origin: tuple = (0.0, 0.0), world_size: tuple = None, mode: str = 'fbm', octaves: int = 4, scale: float = 1.0) -> HeightMap:
+ """Sample noise and multiply with current values. Useful for applying noise-based masks."""
+ ...
+ def normalize(self, min: float = 0.0, max: float = 1.0, *, pos=None, size=None) -> HeightMap:
+ """Linearly rescale values in region. Current min becomes new min, current max becomes new max."""
+ ...
+ def rain_erosion(self, drops: int, erosion: float = 0.1, sedimentation: float = 0.05, seed: int = None) -> HeightMap:
+ """Simulate rain erosion on the terrain."""
+ ...
+ def scale(self, factor: float, *, pos=None, size=None) -> HeightMap:
+ """Multiply cells in region by a factor."""
+ ...
+ def smooth(self, iterations: int = 1) -> HeightMap:
+ """Smooth the heightmap by averaging neighboring cells."""
+ ...
+ def sparse_kernel(self, weights: dict[tuple[int, int], float]) -> HeightMap:
+ """Apply sparse convolution kernel, returning a NEW HeightMap with results."""
+ ...
+ def sparse_kernel_from(self, source: HeightMap, weights: dict[tuple[int, int], float]) -> None:
+ """Apply sparse convolution from source heightmap into self (for reusing destination buffers)."""
+ ...
+ def subtract(self, other: HeightMap, *, pos=None, source_pos=None, size=None) -> HeightMap:
+ """Subtract another heightmap's values from this one in the specified region."""
+ ...
+ def threshold(self, range: tuple[float, float]) -> HeightMap:
+ """Return NEW HeightMap with original values where in range, 0.0 elsewhere."""
+ ...
+ def threshold_binary(self, range: tuple[float, float], value: float = 1.0) -> HeightMap:
+ """Return NEW HeightMap with uniform value where in range, 0.0 elsewhere."""
+ ...
+
+class Keyboard:
+ """Keyboard state singleton for checking modifier keys"""
+ def __init__(self, *args, **kwargs) -> None: ...
+ alt: Any # True if either Alt key is currently pressed (read-only).
+ ctrl: Any # True if either Control key is currently pressed (read-only).
+ shift: Any # True if either Shift key is currently pressed (read-only).
+ system: Any # True if either System key (Win/Cmd) is currently pressed (read-only).
+
+class LdtkProject:
+ """Load an LDtk project file (.ldtk)."""
+ def __init__(self, path: str) -> None: ...
+ enums: Any # Enum definitions from the project as a list of dicts (read-only).
+ level_names: Any # List of level identifier names (list[str], read-only).
+ ruleset_names: Any # List of rule set / layer names (list[str], read-only).
+ tileset_names: Any # List of tileset identifier names (list[str], read-only).
+ version: str # LDtk JSON format version string (str, read-only).
+ def level(self, name: str) -> dict:
+ """Get level data by name."""
+ ...
+ def ruleset(self, name: str) -> AutoRuleSet:
+ """Get an auto-rule set by layer name."""
+ ...
+ def tileset(self, name: str) -> TileSetFile:
+ """Get a tileset by name."""
+ ...
+
+class Line:
+ """A line UI element for drawing straight lines between two points."""
+ def __init__(self, start=None, end=None, thickness=1.0, color=None, **kwargs) -> None: ...
+ align: Any # Alignment relative to parent bounds (Alignment enum or None). When set, position is automatically calculated when parent is assigned or resized. Set to None ...
+ bounds: Any # Bounding box as (pos, size) tuple of Vectors. Returns (Vector(x, y), Vector(width, height)).
+ color: Any # Line color as a Color object.
+ end: Any # Ending point of the line as a Vector.
+ global_bounds: Any # Bounding box as (pos, size) tuple of Vectors in screen coordinates. Returns (Vector(x, y), Vector(width, height)).
+ global_position: Any # Global screen position (read-only). Calculates absolute position by walking up the parent chain.
+ grid_pos: Any # Position in grid tile coordinates (only when parent is Grid)
+ grid_size: Any # Size in grid tile coordinates (only when parent is Grid)
+ horiz_margin: float # Horizontal margin override (float, 0 = use general margin). Invalid for vertically-centered alignments (TOP_CENTER, BOTTOM_CENTER, CENTER).
+ hovered: Any # Whether mouse is currently over this element (read-only). Updated automatically by the engine during mouse movement.
+ margin: float # General margin from edge when aligned (float). Applied to both horizontal and vertical edges unless overridden. Invalid for CENTER alignment (raises ValueErr...
+ name: Any # Name for finding this element.
+ on_click: Any # Callable executed when line is clicked. Function receives (pos: Vector, button: str, action: str).
+ on_enter: Any # Callback for mouse enter events. Called with (pos: Vector, button: str, action: str) when mouse enters this element's bounds.
+ on_exit: Any # Callback for mouse exit events. Called with (pos: Vector, button: str, action: str) when mouse leaves this element's bounds.
+ on_move: Any # Callback for mouse movement within bounds. Called with (pos: Vector, button: str, action: str) for each mouse movement while inside. Performance note: Called...
+ opacity: Any # Opacity level (0.0 = transparent, 1.0 = opaque). Automatically clamped to valid range [0.0, 1.0].
+ origin: Any # Transform origin as Vector (pivot point for rotation). Default (0,0) is top-left; set to (w/2, h/2) to rotate around center.
+ parent: Any # Parent drawable. Get: Returns the parent Frame/Grid if nested, or None if at scene level. Set: Assign a Frame/Grid to reparent, or None to remove from parent.
+ pos: Any # Position as a Vector (midpoint of line).
+ rotate_with_camera: bool # Whether to rotate visually with parent Grid's camera_rotation (bool). False (default): stay screen-aligned. True: tilt with camera. Only affects children of ...
+ rotation: Any # Rotation angle in degrees (clockwise around origin). Animatable property.
+ start: Any # Starting point of the line as a Vector.
+ thickness: Any # Line thickness in pixels.
+ vert_margin: float # Vertical margin override (float, 0 = use general margin). Invalid for horizontally-centered alignments (CENTER_LEFT, CENTER_RIGHT, CENTER).
+ visible: bool # Whether the object is visible (bool). Invisible objects are not rendered or clickable.
+ z_index: Any # Z-order for rendering (lower values rendered first).
+ def animate(self, property: str, target: Any, duration: float, easing=None, delta=False, loop=False, callback=None, conflict_mode='replace') -> Animation:
+ """Create and start an animation on this drawable's property."""
+ ...
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def realign(self) -> None:
+ """Reapply alignment relative to parent, useful for responsive layouts."""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
+
+class Model3D:
+ """A 3D model resource that can be rendered by Entity3D."""
+ def __init__(self, path=None) -> None: ...
+ animation_clips: Any # List of animation clip names (read-only)
+ bone_count: Any # Number of bones in skeleton (read-only)
+ bounds: Any # AABB as ((min_x, min_y, min_z), (max_x, max_y, max_z)) (read-only)
+ has_skeleton: Any # Whether model has skeletal animation data (read-only)
+ mesh_count: Any # Number of submeshes (read-only)
+ name: Any # Model name (read-only)
+ triangle_count: Any # Total triangle count across all meshes (read-only)
+ vertex_count: Any # Total vertex count across all meshes (read-only)
+ def cube(self, size=1.0) -> Model3D:
+ """Create a unit cube centered at origin."""
+ ...
+ def plane(self, width=1.0, depth=1.0, segments=1) -> Model3D:
+ """Create a flat plane."""
+ ...
+ def sphere(self, radius=0.5, segments=16, rings=12) -> Model3D:
+ """Create a UV sphere."""
+ ...
+
+class Mouse:
+ """Mouse state singleton for reading button/position state and controlling cursor visibility"""
+ def __init__(self, *args, **kwargs) -> None: ...
+ grabbed: Any # Whether the mouse cursor is confined to the window (default: False).
+ left: Any # True if left mouse button is currently pressed (read-only).
+ middle: Any # True if middle mouse button is currently pressed (read-only).
+ pos: Any # Current mouse position as Vector (read-only).
+ right: Any # True if right mouse button is currently pressed (read-only).
+ visible: Any # Whether the mouse cursor is visible (default: True).
+ x: Any # Current mouse X position in window coordinates (read-only).
+ y: Any # Current mouse Y position in window coordinates (read-only).
+
+class Music:
+ """Streaming music object for longer audio tracks"""
+ def __init__(self, *args, **kwargs) -> None: ...
+ duration: Any # Total duration of the music in seconds (read-only).
+ loop: Any # Whether the music loops when it reaches the end.
+ playing: Any # True if the music is currently playing (read-only).
+ position: Any # Current playback position in seconds. Can be set to seek.
+ source: Any # Filename path used to load this music (read-only).
+ volume: Any # Volume level from 0 (silent) to 100 (full volume).
+ def pause(self) -> None:
+ """Pause the music. Use play() to resume from the paused position."""
+ ...
+ def play(self) -> None:
+ """Start or resume playing the music."""
+ ...
+ def stop(self) -> None:
+ """Stop playing and reset to the beginning."""
+ ...
+
+class NoiseSource:
+ """A configured noise generator for procedural generation."""
+ def __init__(self, dimensions: int = 2, algorithm: str = 'simplex', hurst: float = 0.5, lacunarity: float = 2.0, seed: int = None) -> None: ...
+ algorithm: Any # Noise algorithm name ('simplex', 'perlin', or 'wavelet'). Read-only.
+ dimensions: Any # Number of input dimensions (1-4). Read-only.
+ hurst: Any # Hurst exponent for fbm/turbulence. Read-only.
+ lacunarity: Any # Frequency multiplier between octaves. Read-only.
+ seed: Any # Random seed used (even if originally None). Read-only.
+ def fbm(self, pos: tuple[float, ...], octaves: int = 4) -> float:
+ """Get fractal brownian motion value at coordinates."""
+ ...
+ def get(self, pos: tuple[float, ...]) -> float:
+ """Get flat noise value at coordinates."""
+ ...
+ def sample(self, size: tuple[int, int], world_origin: tuple[float, float] = (0.0, 0.0), world_size: tuple[float, float] = None, mode: str = 'fbm', octaves: int = 4) -> HeightMap:
+ """Sample noise into a HeightMap for batch processing."""
+ ...
+ def turbulence(self, pos: tuple[float, ...], octaves: int = 4) -> float:
+ """Get turbulence (absolute fbm) value at coordinates."""
+ ...
+
+class PropertyBinding:
+ """A binding that reads a property value from a UI drawable."""
+ def __init__(self, target: UIDrawable, property: str) -> None: ...
+ is_valid: bool # True if the binding target still exists and property is valid (bool, read-only).
+ property: str # The property name being read (str, read-only).
+ target: Any # The drawable this binding reads from (read-only).
+ value: float # Current value of the binding (float, read-only). Returns None if invalid.
+
+class Scene:
+ """Object-oriented scene management with lifecycle callbacks."""
+ def __init__(self, name: str) -> None: ...
+ active: bool # Whether this scene is currently active (bool, read-only). Only one scene can be active at a time.
+ children: UICollection # UI element collection for this scene (UICollection, read-only). Use to add, remove, or iterate over UI elements. Changes are reflected immediately.
+ name: str # Scene name (str, read-only). Unique identifier for this scene.
+ on_key: Any # Keyboard event handler (callable or None). Function receives (key: Key, action: InputState) for keyboard events. Set to None to remove the handler.
+ opacity: Any # Scene opacity (0.0-1.0). Applied to all UI elements during rendering.
+ pos: Vector # Scene position offset (Vector). Applied to all UI elements during rendering.
+ registered: bool # Whether this scene is registered with the game engine (bool, read-only). Unregistered scenes still exist but won't receive lifecycle callbacks.
+ visible: bool # Scene visibility (bool). If False, scene is not rendered.
+ def activate(self, transition: Transition = None, duration: float = None) -> None:
+ """Make this the active scene with optional transition effect."""
+ ...
+ def realign(self) -> None:
+ """Recalculate alignment for all children with alignment set."""
+ ...
+ def register(self) -> None:
+ """Register this scene with the game engine."""
+ ...
+ def unregister(self) -> None:
+ """Unregister this scene from the game engine."""
+ ...
+
+class Shader:
+ """A GPU shader program for visual effects."""
+ def __init__(self, fragment_source: str, dynamic: bool = False) -> None: ...
+ dynamic: bool # Whether this shader uses time-varying effects (bool). Dynamic shaders invalidate parent caches each frame.
+ is_valid: bool # True if the shader compiled successfully (bool, read-only).
+ source: str # The GLSL fragment shader source code (str, read-only).
+ def set_uniform(self, name: str, value: float|tuple) -> None:
+ """Set a custom uniform value on this shader."""
+ ...
+
+class Sound:
+ """Sound effect object for short audio clips."""
+ def __init__(self, source) -> None: ...
+ buffer: Any # The SoundBuffer if created from one, else None (read-only).
+ duration: Any # Total duration of the sound in seconds (read-only).
+ loop: Any # Whether the sound loops when it reaches the end.
+ pitch: Any # Playback pitch multiplier (1.0 = normal, >1 = higher, <1 = lower).
+ playing: Any # True if the sound is currently playing (read-only).
+ source: Any # Filename path used to load this sound (read-only).
+ volume: Any # Volume level from 0 (silent) to 100 (full volume).
+ def pause(self) -> None:
+ """Pause the sound. Use play() to resume from the paused position."""
+ ...
+ def play(self) -> None:
+ """Start or resume playing the sound."""
+ ...
+ def play_varied(self, pitch_range: float = 0.1, volume_range: float = 3.0) -> None:
+ """Play with randomized pitch and volume for natural variation."""
+ ...
+ def stop(self) -> None:
+ """Stop playing and reset to the beginning."""
+ ...
+
+class SoundBuffer:
+ """SoundBuffer.from_samples(data: bytes, channels: int, sample_rate: int)"""
+ def __init__(self, filename: str) -> None: ...
+ channels: Any # Number of audio channels (read-only).
+ duration: Any # Total duration in seconds (read-only).
+ sample_count: Any # Total number of samples (read-only).
+ sample_rate: Any # Sample rate in Hz (read-only).
+ sfxr_params: Any # Dict of sfxr parameters if sfxr-generated, else None (read-only).
+ def bit_crush(self, bits: int, rate_divisor: int) -> SoundBuffer:
+ """Reduce bit depth and sample rate for lo-fi effect."""
+ ...
+ def concat(self, buffers: list[SoundBuffer], overlap: float = 0.0) -> SoundBuffer:
+ """Concatenate multiple SoundBuffers with optional crossfade overlap."""
+ ...
+ def distortion(self, drive: float) -> SoundBuffer:
+ """Apply tanh soft clipping distortion."""
+ ...
+ def echo(self, delay_ms: float, feedback: float, wet: float) -> SoundBuffer:
+ """Apply echo effect with delay, feedback, and wet/dry mix."""
+ ...
+ def from_samples(self, data: bytes, channels: int, sample_rate: int) -> SoundBuffer:
+ """Create a SoundBuffer from raw int16 PCM sample data."""
+ ...
+ def gain(self, factor: float) -> SoundBuffer:
+ """Multiply all samples by a scalar factor. Use for volume/amplitude control before mixing."""
+ ...
+ def high_pass(self, cutoff_hz: float) -> SoundBuffer:
+ """Apply single-pole IIR high-pass filter."""
+ ...
+ def low_pass(self, cutoff_hz: float) -> SoundBuffer:
+ """Apply single-pole IIR low-pass filter."""
+ ...
+ def mix(self, buffers: list[SoundBuffer]) -> SoundBuffer:
+ """Mix multiple SoundBuffers together (additive, clamped)."""
+ ...
+ def normalize(self) -> SoundBuffer:
+ """Scale samples to 95%% of int16 max."""
+ ...
+ def pitch_shift(self, factor: float) -> SoundBuffer:
+ """Resample to shift pitch. factor>1 = higher+shorter."""
+ ...
+ def reverb(self, room_size: float, damping: float, wet: float) -> SoundBuffer:
+ """Apply simplified Freeverb-style reverb."""
+ ...
+ def reverse(self) -> SoundBuffer:
+ """Reverse the sample order."""
+ ...
+ def sfxr(self, preset: str = None, seed: int = None, **params) -> SoundBuffer:
+ """Generate retro sound effects using sfxr synthesis."""
+ ...
+ def sfxr_mutate(self, amount: float = 0.05, seed: int = None) -> SoundBuffer:
+ """Jitter sfxr params and re-synthesize. Only works on sfxr-generated buffers."""
+ ...
+ def slice(self, start: float, end: float) -> SoundBuffer:
+ """Extract a time range in seconds."""
+ ...
+ def tone(self, frequency: float, duration: float, waveform: str = 'sine', **kwargs) -> SoundBuffer:
+ """Generate a tone with optional ADSR envelope."""
+ ...
+
+class Sprite:
+ """A sprite UI element that displays a texture or portion of a texture atlas."""
+ def __init__(self, pos=None, texture=None, sprite_index=0, **kwargs) -> None: ...
+ align: Any # Alignment relative to parent bounds (Alignment enum or None). When set, position is automatically calculated when parent is assigned or resized. Set to None ...
+ bounds: Any # Bounding box as (pos, size) tuple of Vectors. Returns (Vector(x, y), Vector(width, height)).
+ global_bounds: Any # Bounding box as (pos, size) tuple of Vectors in screen coordinates. Returns (Vector(x, y), Vector(width, height)).
+ global_position: Any # Global screen position (read-only). Calculates absolute position by walking up the parent chain.
+ grid_pos: Any # Position in grid tile coordinates (only when parent is Grid)
+ grid_size: Any # Size in grid tile coordinates (only when parent is Grid)
+ horiz_margin: float # Horizontal margin override (float, 0 = use general margin). Invalid for vertically-centered alignments (TOP_CENTER, BOTTOM_CENTER, CENTER).
+ hovered: Any # Whether mouse is currently over this element (read-only). Updated automatically by the engine during mouse movement.
+ margin: float # General margin from edge when aligned (float). Applied to both horizontal and vertical edges unless overridden. Invalid for CENTER alignment (raises ValueErr...
+ name: Any # Name for finding elements
+ on_click: Any # Callable executed when object is clicked. Function receives (pos: Vector, button: str, action: str).
+ on_enter: Any # Callback for mouse enter events. Called with (pos: Vector, button: str, action: str) when mouse enters this element's bounds.
+ on_exit: Any # Callback for mouse exit events. Called with (pos: Vector, button: str, action: str) when mouse leaves this element's bounds.
+ on_move: Any # Callback for mouse movement within bounds. Called with (pos: Vector, button: str, action: str) for each mouse movement while inside. Performance note: Called...
+ opacity: Any # Opacity level (0.0 = transparent, 1.0 = opaque). Automatically clamped to valid range [0.0, 1.0].
+ origin: Any # Transform origin as Vector (pivot point for rotation). Default (0,0) is top-left; set to (w/2, h/2) to rotate around center.
+ parent: Any # Parent drawable. Get: Returns the parent Frame/Grid if nested, or None if at scene level. Set: Assign a Frame/Grid to reparent, or None to remove from parent.
+ pos: Any # Position as a Vector
+ rotate_with_camera: bool # Whether to rotate visually with parent Grid's camera_rotation (bool). False (default): stay screen-aligned. True: tilt with camera. Only affects children of ...
+ rotation: Any # Rotation angle in degrees (clockwise around origin). Animatable property.
+ scale: Any # Uniform size factor
+ scale_x: Any # Horizontal scale factor
+ scale_y: Any # Vertical scale factor
+ shader: Any # Shader for GPU visual effects (Shader or None). When set, the drawable is rendered through the shader program. Set to None to disable shader effects.
+ sprite_index: Any # Which sprite on the texture is shown
+ texture: Any # Texture object
+ uniforms: Any # Collection of shader uniforms (read-only access to collection). Set uniforms via dict-like syntax: drawable.uniforms['name'] = value. Supports float, vec2/3/...
+ vert_margin: float # Vertical margin override (float, 0 = use general margin). Invalid for horizontally-centered alignments (CENTER_LEFT, CENTER_RIGHT, CENTER).
+ visible: bool # Whether the object is visible (bool). Invisible objects are not rendered or clickable.
+ x: Any # X coordinate of top-left corner
+ y: Any # Y coordinate of top-left corner
+ z_index: Any # Z-order for rendering (lower values rendered first). Automatically triggers scene resort when changed.
+ def animate(self, property: str, target: Any, duration: float, easing=None, delta=False, loop=False, callback=None, conflict_mode='replace') -> Animation:
+ """Create and start an animation on this drawable's property."""
+ ...
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def realign(self) -> None:
+ """Reapply alignment relative to parent, useful for responsive layouts."""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
+
+class Texture:
+ """A texture atlas for sprites and tiles."""
+ def __init__(self, filename: str, sprite_width: int = 0, sprite_height: int = 0, display_size: tuple = None, display_origin: tuple = None) -> None: ...
+ display_height: int # Display height of sprite content within each cell (int, read-only). Defaults to sprite_height.
+ display_offset_x: int # X offset of sprite content within each cell (int, read-only). Default 0.
+ display_offset_y: int # Y offset of sprite content within each cell (int, read-only). Default 0.
+ display_width: int # Display width of sprite content within each cell (int, read-only). Defaults to sprite_width.
+ sheet_height: int # Number of sprite rows in the texture sheet (int, read-only). Calculated as texture_height / sprite_height.
+ sheet_width: int # Number of sprite columns in the texture sheet (int, read-only). Calculated as texture_width / sprite_width.
+ source: str # Source filename path (str, read-only). The path used to load this texture.
+ sprite_count: int # Total number of sprites in the texture sheet (int, read-only). Equals sheet_width * sheet_height.
+ sprite_height: int # Height of each sprite in pixels (int, read-only). Specified during texture initialization.
+ sprite_width: int # Width of each sprite in pixels (int, read-only). Specified during texture initialization.
+ def composite(self, layers: list[Texture], sprite_width: int, sprite_height: int, name: str = '') -> Texture:
+ """Alpha-composite multiple texture layers into a single texture."""
+ ...
+ def from_bytes(self, data: bytes, width: int, height: int, sprite_width: int, sprite_height: int, name: str = '') -> Texture:
+ """Create a Texture from raw RGBA pixel data."""
+ ...
+ def hsl_shift(self, hue_shift: float, sat_shift: float = 0.0, lit_shift: float = 0.0) -> Texture:
+ """Create a new texture with HSL color adjustments applied."""
+ ...
+
+class TileLayer:
+ """A grid layer that stores sprite indices per cell for tile-based rendering."""
+ def __init__(self, z_index=-1, name=None, texture=None, grid_size=None) -> None: ...
+ grid: Any # Parent Grid or None. Setting manages layer association and handles lazy allocation.
+ grid_size: Any # Layer dimensions as (width, height) tuple.
+ name: str # Layer name (str, read-only). Used for Grid.layer(name) lookup.
+ texture: Any # Texture atlas for tile sprites.
+ visible: Any # Whether the layer is rendered.
+ z_index: Any # Layer z-order. Negative values render below entities.
+ def apply_ranges(self, source, ranges) -> TileLayer:
+ """Apply multiple tile assignments in a single pass."""
+ ...
+ def apply_threshold(self, source, range, tile) -> TileLayer:
+ """Set tile index for cells where HeightMap value is within range."""
+ ...
+ def at(self, pos) -> int:
+ """at(x, y) -> int"""
+ ...
+ def fill(self, index) -> Any:
+ """Fill the entire layer with the specified tile index."""
+ ...
+ def fill_rect(self, pos, size, index) -> Any:
+ """Fill a rectangular region with a tile index."""
+ ...
+ def set(self, pos, index) -> Any:
+ """Set the tile index at cell position. Use -1 for no tile."""
+ ...
+
+class TileMapFile:
+ """Load a Tiled map file (.tmx or .tmj)."""
+ def __init__(self, path: str) -> None: ...
+ height: int # Map height in tiles (int, read-only).
+ object_layer_names: Any # List of object layer names (read-only).
+ orientation: str # Map orientation, e.g. 'orthogonal' (str, read-only).
+ properties: Any # Custom map properties as a dict (read-only).
+ tile_height: int # Tile height in pixels (int, read-only).
+ tile_layer_names: Any # List of tile layer names (read-only).
+ tile_width: int # Tile width in pixels (int, read-only).
+ tileset_count: int # Number of referenced tilesets (int, read-only).
+ width: int # Map width in tiles (int, read-only).
+ def apply_to_tile_layer(self, tile_layer: TileLayer, layer_name: str, tileset_index: int = 0) -> None:
+ """Resolve GIDs and write sprite indices into a TileLayer."""
+ ...
+ def object_layer(self, name: str) -> list[dict]:
+ """Get objects from an object layer as Python dicts."""
+ ...
+ def resolve_gid(self, gid: int) -> tuple[int, int]:
+ """Resolve a global tile ID to tileset index and local tile ID."""
+ ...
+ def tile_layer_data(self, name: str) -> list[int]:
+ """Get raw global GID data for a tile layer."""
+ ...
+ def tileset(self, index: int) -> tuple[int, TileSetFile]:
+ """Get a referenced tileset by index."""
+ ...
+
+class TileSetFile:
+ """Load a Tiled tileset file (.tsx or .tsj)."""
+ def __init__(self, path: str) -> None: ...
+ columns: int # Number of columns in tileset image (int, read-only).
+ image_source: str # Resolved path to the tileset image file (str, read-only).
+ margin: int # Margin around tiles in pixels (int, read-only).
+ name: str # Tileset name (str, read-only).
+ properties: Any # Custom tileset properties as a dict (read-only).
+ spacing: int # Spacing between tiles in pixels (int, read-only).
+ tile_count: int # Total number of tiles (int, read-only).
+ tile_height: int # Height of each tile in pixels (int, read-only).
+ tile_width: int # Width of each tile in pixels (int, read-only).
+ wang_sets: Any # List of WangSet objects from this tileset (read-only).
+ def tile_info(self, tile_id: int) -> dict | None:
+ """Get metadata for a specific tile."""
+ ...
+ def to_texture(self) -> Texture:
+ """Create a Texture from the tileset image."""
+ ...
+ def wang_set(self, name: str) -> WangSet:
+ """Look up a WangSet by name."""
+ ...
+
+class Timer:
+ """Create a timer that calls a function at regular intervals."""
+ def __init__(self, name, callback, interval, once=False, start=True) -> None: ...
+ active: bool # Running state (bool, read-write). True if running (not paused, not stopped). Set True to start/resume, False to pause.
+ callback: Callable # The callback function (callable). Preserved when stopped, allowing timer restart.
+ interval: int # Timer interval in milliseconds (int). Must be positive. Can be changed while timer is running.
+ name: str # Timer name (str, read-only). Unique identifier for this timer.
+ once: bool # Whether the timer stops after firing once (bool). One-shot timers can be restarted.
+ paused: bool # Whether the timer is paused (bool, read-only). Paused timers preserve their remaining time.
+ remaining: int # Time remaining until next trigger in milliseconds (int, read-only). Full interval when stopped.
+ stopped: bool # Whether the timer is stopped (bool, read-only). Stopped timers are not in the engine tick loop but preserve their callback.
+ def pause(self) -> None:
+ """Pause the timer, preserving the time remaining until next trigger."""
+ ...
+ def restart(self) -> None:
+ """Restart the timer from the beginning and ensure it's running."""
+ ...
+ def resume(self) -> None:
+ """Resume a paused timer from where it left off."""
+ ...
+ def start(self) -> None:
+ """Start the timer, adding it to the engine tick loop."""
+ ...
+ def stop(self) -> None:
+ """Stop the timer and remove it from the engine tick loop."""
+ ...
+
+class Vector:
+ """2D vector for positions, sizes, and directions."""
+ def __init__(self, x: float = 0, y: float = 0) -> None: ...
+ int: Any # Integer tuple (floor of x and y) for use as dict keys. Read-only.
+ x: float # X coordinate of the vector (float)
+ y: float # Y coordinate of the vector (float)
+ def angle(self) -> float:
+ """Get the angle of this vector in radians."""
+ ...
+ def copy(self) -> Vector:
+ """Create a copy of this vector."""
+ ...
+ def distance_to(self, other: Vector) -> float:
+ """Calculate the distance to another vector."""
+ ...
+ def dot(self, other: Vector) -> float:
+ """Calculate the dot product with another vector."""
+ ...
+ def floor(self) -> Vector:
+ """Return a new vector with floored (integer) coordinates."""
+ ...
+ def magnitude(self) -> float:
+ """Calculate the length/magnitude of this vector."""
+ ...
+ def magnitude_squared(self) -> float:
+ """Calculate the squared magnitude of this vector."""
+ ...
+ def normalize(self) -> Vector:
+ """Return a unit vector in the same direction."""
+ ...
+
+class Viewport3D:
+ """A 3D rendering viewport that displays a 3D scene as a UI element."""
+ def __init__(self, pos=None, size=None, **kwargs) -> None: ...
+ bg_color: Any # Background clear color.
+ bounds: Any # Bounding box as (pos, size) tuple of Vectors. Returns (Vector(x, y), Vector(width, height)).
+ camera_pos: Any # Camera position as (x, y, z) tuple.
+ camera_target: Any # Camera look-at target as (x, y, z) tuple.
+ cell_size: Any # World units per navigation grid cell.
+ enable_affine: Any # Enable PS1-style affine texture mapping (warped textures).
+ enable_dither: Any # Enable PS1-style color dithering.
+ enable_fog: Any # Enable distance fog.
+ enable_vertex_snap: Any # Enable PS1-style vertex snapping (jittery vertices).
+ entities: Any # Collection of Entity3D objects (read-only). Use append/remove to modify.
+ fog_color: Any # Fog color.
+ fog_far: Any # Fog end distance.
+ fog_near: Any # Fog start distance.
+ fov: Any # Camera field of view in degrees.
+ global_bounds: Any # Bounding box as (pos, size) tuple of Vectors in screen coordinates. Returns (Vector(x, y), Vector(width, height)).
+ global_position: Any # Global screen position (read-only). Calculates absolute position by walking up the parent chain.
+ grid_size: Any # Navigation grid dimensions as (width, depth) tuple.
+ h: Any # Display height in pixels.
+ hovered: Any # Whether mouse is currently over this element (read-only). Updated automatically by the engine during mouse movement.
+ on_click: Any # Callable executed when object is clicked. Function receives (pos: Vector, button: str, action: str).
+ on_enter: Any # Callback for mouse enter events. Called with (pos: Vector, button: str, action: str) when mouse enters this element's bounds.
+ on_exit: Any # Callback for mouse exit events. Called with (pos: Vector, button: str, action: str) when mouse leaves this element's bounds.
+ on_move: Any # Callback for mouse movement within bounds. Called with (pos: Vector, button: str, action: str) for each mouse movement while inside. Performance note: Called...
+ opacity: Any # Opacity level (0.0 = transparent, 1.0 = opaque). Automatically clamped to valid range [0.0, 1.0].
+ parent: Any # Parent drawable. Get: Returns the parent Frame/Grid if nested, or None if at scene level. Set: Assign a Frame/Grid to reparent, or None to remove from parent.
+ pos: Any # Position as Vector (x, y).
+ render_resolution: Any # Internal render resolution (width, height). Lower values for PS1 effect.
+ visible: bool # Whether the object is visible (bool). Invisible objects are not rendered or clickable.
+ w: Any # Display width in pixels.
+ x: Any # X position in pixels.
+ y: Any # Y position in pixels.
+ z_index: Any # Z-order for rendering (lower values rendered first). Automatically triggers scene resort when changed.
+ def add_billboard(self, billboard) -> Any:
+ """Add a Billboard to the viewport."""
+ ...
+ def add_layer(self, name, z_index=0) -> dict:
+ """Add a new mesh layer to the viewport."""
+ ...
+ def add_mesh(self, layer_name, model, pos, rotation=0, scale=1.0) -> int:
+ """Add a Model3D instance to a layer at the specified position."""
+ ...
+ def add_voxel_layer(self, voxel_grid, z_index=0) -> Any:
+ """Add a VoxelGrid as a renderable layer."""
+ ...
+ def animate(self, property: str, target: Any, duration: float, easing=None, delta=False, loop=False, callback=None, conflict_mode='replace') -> Animation:
+ """Create and start an animation on this drawable's property."""
+ ...
+ def apply_heightmap(self, heightmap, y_scale=1.0) -> Any:
+ """Set cell heights from HeightMap."""
+ ...
+ def apply_terrain_colors(self, layer_name, r_map, g_map, b_map) -> Any:
+ """Apply per-vertex colors to terrain from RGB HeightMaps."""
+ ...
+ def apply_threshold(self, heightmap, min_height, max_height, walkable=True) -> Any:
+ """Set cell walkability based on height thresholds."""
+ ...
+ def at(self, x, z) -> VoxelPoint:
+ """Get VoxelPoint at grid coordinates."""
+ ...
+ def billboard_count(self) -> int:
+ """Get the number of billboards."""
+ ...
+ def build_terrain(self, layer_name, heightmap, y_scale=1.0, cell_size=1.0) -> int:
+ """Build terrain mesh from HeightMap on specified layer."""
+ ...
+ def clear_billboards(self) -> Any:
+ """Remove all billboards from the viewport."""
+ ...
+ def clear_meshes(self, layer_name) -> Any:
+ """Clear all mesh instances from a layer."""
+ ...
+ def clear_voxel_nav_region(self, voxel_grid) -> Any:
+ """Clear navigation cells in a voxel grid's footprint."""
+ ...
+ def compute_fov(self, origin, radius=10) -> list:
+ """Compute field of view from a position."""
+ ...
+ def find_path(self, start, end) -> list:
+ """Find A* path between two points."""
+ ...
+ def follow(self, entity, distance=10, height=5, smoothing=1.0) -> Any:
+ """Position camera to follow an entity."""
+ ...
+ def get_billboard(self, index) -> Billboard:
+ """Get a Billboard by index."""
+ ...
+ def get_layer(self, name) -> dict or None:
+ """Get a layer by name."""
+ ...
+ def is_in_fov(self, x, z) -> bool:
+ """Check if a cell is in the current FOV (after compute_fov)."""
+ ...
+ def layer_count(self) -> int:
+ """Get the number of mesh layers."""
+ ...
+ def move(self, *args, **kwargs) -> Any:
+ """move(dx, dy) or (delta) -> None"""
+ ...
+ def orbit_camera(self, angle=0, distance=10, height=5) -> Any:
+ """Position camera to orbit around origin."""
+ ...
+ def place_blocking(self, grid_pos, footprint, walkable=False, transparent=False) -> Any:
+ """Mark grid cells as blocking for pathfinding and FOV."""
+ ...
+ def project_all_voxels_to_nav(self, headroom=2) -> Any:
+ """Project all voxel layers to the navigation grid."""
+ ...
+ def project_voxel_to_nav(self, voxel_grid, headroom=2) -> Any:
+ """Project a VoxelGrid to the navigation grid."""
+ ...
+ def realign(self) -> None:
+ """Reapply alignment relative to parent, useful for responsive layouts."""
+ ...
+ def remove_billboard(self, billboard) -> Any:
+ """Remove a Billboard from the viewport."""
+ ...
+ def remove_layer(self, name) -> bool:
+ """Remove a layer by name. Returns True if found and removed."""
+ ...
+ def remove_voxel_layer(self, voxel_grid) -> bool:
+ """Remove a VoxelGrid layer from the viewport."""
+ ...
+ def resize(self, *args, **kwargs) -> Any:
+ """resize(width, height) or (size) -> None"""
+ ...
+ def screen_to_world(self, x, y, y_plane=0.0) -> tuple or None:
+ """Convert screen coordinates to world position via ray casting."""
+ ...
+ def set_grid_size(self, width, depth) -> Any:
+ """Initialize navigation grid with specified dimensions."""
+ ...
+ def set_slope_cost(self, max_slope=0.5, cost_multiplier=1.0) -> Any:
+ """Calculate slope costs and mark steep cells unwalkable."""
+ ...
+ def voxel_layer_count(self) -> int:
+ """Get the number of voxel layers."""
+ ...
+
+class VoxelGrid:
+ """A dense 3D grid of voxel material IDs with a material palette."""
+ def __init__(self, size: tuple[int, int, int], cell_size: float = 1.0) -> None: ...
+ cell_size: Any # World units per voxel. Read-only.
+ depth: Any # Grid depth (Z dimension). Read-only.
+ greedy_meshing: Any # Enable greedy meshing optimization (reduces vertex count for uniform regions).
+ height: Any # Grid height (Y dimension). Read-only.
+ material_count: Any # Number of materials in the palette. Read-only.
+ offset: Any # World-space position (x, y, z) of the grid origin.
+ rotation: Any # Y-axis rotation in degrees.
+ size: Any # Dimensions (width, height, depth) of the grid. Read-only.
+ vertex_count: Any # Number of vertices after mesh generation. Read-only.
+ visible: Any # Show or hide this voxel grid in rendering.
+ width: Any # Grid width (X dimension). Read-only.
+ def add_material(self, name, color=Color(255, 255, 255), sprite_index=-1, transparent=False, path_cost=1.0) -> int:
+ """Add a new material to the palette. Returns the material ID (1-indexed)."""
+ ...
+ def clear(self) -> None:
+ """Clear the grid (fill with air, material 0)."""
+ ...
+ def copy_region(self, min_coord, max_coord) -> VoxelRegion:
+ """Copy a rectangular region to a VoxelRegion prefab."""
+ ...
+ def count_material(self, material) -> int:
+ """Count the number of voxels with the specified material ID."""
+ ...
+ def count_non_air(self) -> int:
+ """Count the number of non-air voxels in the grid."""
+ ...
+ def fill(self, material) -> None:
+ """Fill the entire grid with the specified material ID."""
+ ...
+ def fill_box(self, min_coord, max_coord, material) -> None:
+ """Fill a rectangular region with the specified material."""
+ ...
+ def fill_box_hollow(self, min_coord, max_coord, material, thickness=1) -> None:
+ """Create a hollow rectangular room (walls only, hollow inside)."""
+ ...
+ def fill_cylinder(self, base_pos, radius, height, material) -> None:
+ """Fill a vertical cylinder (Y-axis aligned)."""
+ ...
+ def fill_noise(self, min_coord, max_coord, material, threshold=0.5, scale=0.1, seed=0) -> None:
+ """Fill region with 3D noise-based pattern (caves, clouds)."""
+ ...
+ def fill_sphere(self, center, radius, material) -> None:
+ """Fill a spherical region."""
+ ...
+ def from_bytes(self, data) -> bool:
+ """Load voxel data from a bytes object."""
+ ...
+ def get(self, x, y, z) -> int:
+ """Get the material ID at integer coordinates."""
+ ...
+ def get_material(self, id) -> dict:
+ """Get material properties by ID."""
+ ...
+ def load(self, path) -> bool:
+ """Load voxel data from a binary file."""
+ ...
+ def paste_region(self, region, position, skip_air=True) -> None:
+ """Paste a VoxelRegion prefab at the specified position."""
+ ...
+ def project_column(self, x, z, headroom=2) -> dict:
+ """Project a single column to navigation info."""
+ ...
+ def rebuild_mesh(self) -> None:
+ """Force immediate mesh rebuild for rendering."""
+ ...
+ def save(self, path) -> bool:
+ """Save the voxel grid to a binary file."""
+ ...
+ def set(self, x, y, z, material) -> None:
+ """Set the material ID at integer coordinates."""
+ ...
+ def to_bytes(self) -> bytes:
+ """Serialize the voxel grid to a bytes object."""
+ ...
+
+class VoxelRegion:
+ """VoxelRegion - Portable voxel data for copy/paste operations."""
+ def __init__(self, *args, **kwargs) -> None: ...
+ depth: Any # Region depth. Read-only.
+ height: Any # Region height. Read-only.
+ size: Any # Dimensions (width, height, depth) of the region. Read-only.
+ width: Any # Region width. Read-only.
+
+class WangSet:
+ """WangSet - Wang terrain auto-tile set from a Tiled tileset."""
+ def __init__(self, *args, **kwargs) -> None: ...
+ color_count: int # Number of terrain colors (int, read-only).
+ colors: Any # List of color dicts with name, index, tile_id, probability (read-only).
+ name: str # Wang set name (str, read-only).
+ type: str # Wang set type: 'corner', 'edge', or 'mixed' (str, read-only).
+ def apply(self, discrete_map: DiscreteMap, tile_layer: TileLayer) -> None:
+ """Resolve terrain and write tile indices directly into a TileLayer."""
+ ...
+ def resolve(self, discrete_map: DiscreteMap) -> list[int]:
+ """Resolve terrain data to tile indices using Wang tile rules."""
+ ...
+ def terrain_enum(self) -> IntEnum:
+ """Generate a Python IntEnum from this WangSet's terrain colors."""
+ ...
+
+class Window:
+ """Window singleton for accessing and modifying the game window properties"""
+ def __init__(self, *args, **kwargs) -> None: ...
+ framerate_limit: int # Frame rate limit in FPS (int, 0 for unlimited). Caps maximum frame rate.
+ fullscreen: bool # Window fullscreen state (bool). Setting this recreates the window.
+ game_resolution: Any # Fixed game resolution as (width, height) tuple. Enables resolution-independent rendering with scaling.
+ resolution: Any # Window resolution as (width, height) tuple. Setting this recreates the window.
+ scaling_mode: str # Viewport scaling mode (str): 'center' (no scaling), 'stretch' (fill window), or 'fit' (maintain aspect ratio).
+ title: str # Window title string (str). Displayed in the window title bar.
+ visible: bool # Window visibility state (bool). Hidden windows still process events.
+ vsync: bool # Vertical sync enabled state (bool). Prevents screen tearing but may limit framerate.
+ def center(self) -> None:
+ """Center the window on the screen."""
+ ...
+ def get(self) -> Window:
+ """Get the Window singleton instance."""
+ ...
+ def screenshot(self, filename: str = None) -> bytes | None:
+ """Take a screenshot of the current window contents."""
+ ...
+
+# --- Submodules ---------------------------------------------------------
+class _automation_module:
+ """Stub for mcrfpy.automation submodule."""
+ @staticmethod
+ def click(self, *args, **kwargs) -> Any:
+ """click(pos=None, clicks=1, interval=0.0, button='left') - Click at position. Accepts (x,y) tuple, [x,y] list, Vector, or None for current position."""
+ ...
+ @staticmethod
+ def doubleClick(self, *args, **kwargs) -> Any:
+ """doubleClick(pos=None) - Double click at position. Accepts (x,y) tuple, [x,y] list, Vector, or None for current position."""
+ ...
+ @staticmethod
+ def dragRel(self, *args, **kwargs) -> Any:
+ """dragRel(offset, duration=0.0, button='left') - Drag mouse relative to current position. Accepts (x,y) tuple, [x,y] list, or Vector."""
+ ...
+ @staticmethod
+ def dragTo(self, *args, **kwargs) -> Any:
+ """dragTo(pos, duration=0.0, button='left') - Drag mouse to position. Accepts (x,y) tuple, [x,y] list, or Vector."""
+ ...
+ @staticmethod
+ def hotkey(self, *args, **kwargs) -> Any:
+ """hotkey(*keys) - Press a hotkey combination (e.g., hotkey('ctrl', 'c'))"""
+ ...
+ @staticmethod
+ def keyDown(self, *args, **kwargs) -> Any:
+ """keyDown(key) - Press and hold a key"""
+ ...
+ @staticmethod
+ def keyUp(self, *args, **kwargs) -> Any:
+ """keyUp(key) - Release a key"""
+ ...
+ @staticmethod
+ def middleClick(self, *args, **kwargs) -> Any:
+ """middleClick(pos=None) - Middle click at position. Accepts (x,y) tuple, [x,y] list, Vector, or None for current position."""
+ ...
+ @staticmethod
+ def mouseDown(self, *args, **kwargs) -> Any:
+ """mouseDown(pos=None, button='left') - Press mouse button at position. Accepts (x,y) tuple, [x,y] list, Vector, or None for current position."""
+ ...
+ @staticmethod
+ def mouseUp(self, *args, **kwargs) -> Any:
+ """mouseUp(pos=None, button='left') - Release mouse button at position. Accepts (x,y) tuple, [x,y] list, Vector, or None for current position."""
+ ...
+ @staticmethod
+ def moveRel(self, *args, **kwargs) -> Any:
+ """moveRel(offset, duration=0.0) - Move mouse relative to current position. Accepts (x,y) tuple, [x,y] list, or Vector."""
+ ...
+ @staticmethod
+ def moveTo(self, *args, **kwargs) -> Any:
+ """moveTo(pos, duration=0.0) - Move mouse to position. Accepts (x,y) tuple, [x,y] list, or Vector."""
+ ...
+ @staticmethod
+ def onScreen(self, *args, **kwargs) -> Any:
+ """onScreen(pos) - Check if position is within screen bounds. Accepts (x,y) tuple, [x,y] list, or Vector."""
+ ...
+ @staticmethod
+ def position(self, *args, **kwargs) -> Any:
+ """position() - Get current mouse position as Vector"""
+ ...
+ @staticmethod
+ def rightClick(self, *args, **kwargs) -> Any:
+ """rightClick(pos=None) - Right click at position. Accepts (x,y) tuple, [x,y] list, Vector, or None for current position."""
+ ...
+ @staticmethod
+ def screenshot(self, *args, **kwargs) -> Any:
+ """screenshot(filename) - Save a screenshot to the specified file"""
+ ...
+ @staticmethod
+ def scroll(self, *args, **kwargs) -> Any:
+ """scroll(clicks, pos=None) - Scroll wheel at position. Accepts (x,y) tuple, [x,y] list, Vector, or None for current position."""
+ ...
+ @staticmethod
+ def size(self, *args, **kwargs) -> Any:
+ """size() - Get screen size as Vector"""
+ ...
+ @staticmethod
+ def tripleClick(self, *args, **kwargs) -> Any:
+ """tripleClick(pos=None) - Triple click at position. Accepts (x,y) tuple, [x,y] list, Vector, or None for current position."""
+ ...
+ @staticmethod
+ def typewrite(self, *args, **kwargs) -> Any:
+ """typewrite(message, interval=0.0) - Type text with optional interval between keystrokes"""
+ ...
+automation: _automation_module
+
+# --- Module-level functions ---------------------------------------------
+def bresenham(start, end, *, include_start=True, include_end=True) -> list[tuple[int, int]]:
+ """Compute grid cells along a line using Bresenham's algorithm."""
...
-
-def loadMusic(filename: str) -> None:
- """Load and immediately play background music from a file."""
+def end_benchmark() -> str:
+ """Stop benchmark capture and write data to JSON file."""
...
-
-def setMusicVolume(volume: int) -> None:
- """Set the global music volume (0-100)."""
- ...
-
-def setSoundVolume(volume: int) -> None:
- """Set the global sound effects volume (0-100)."""
- ...
-
-def playSound(buffer_id: int) -> None:
- """Play a sound effect using a previously loaded buffer."""
- ...
-
-def getMusicVolume() -> int:
- """Get the current music volume level (0-100)."""
- ...
-
-def getSoundVolume() -> int:
- """Get the current sound effects volume level (0-100)."""
- ...
-
-def sceneUI(scene: Optional[str] = None) -> UICollection:
- """Get all UI elements for a scene."""
- ...
-
-def currentScene() -> str:
- """Get the name of the currently active scene."""
- ...
-
-def setScene(scene: str, transition: Optional[str] = None, duration: float = 0.0) -> None:
- """Switch to a different scene with optional transition effect."""
- ...
-
-def createScene(name: str) -> None:
- """Create a new empty scene."""
- ...
-
-def keypressScene(handler: Callable[[str, bool], None]) -> None:
- """Set the keyboard event handler for the current scene."""
- ...
-
-def setTimer(name: str, handler: Callable[[float], None], interval: int) -> None:
- """Create or update a recurring timer."""
- ...
-
-def delTimer(name: str) -> None:
- """Stop and remove a timer."""
- ...
-
def exit() -> None:
"""Cleanly shut down the game engine and exit the application."""
...
-
-def setScale(multiplier: float) -> None:
- """Scale the game window size (deprecated - use Window.resolution)."""
- ...
-
-def find(name: str, scene: Optional[str] = None) -> Optional[UIElement]:
+def find(name: str, scene: str = None) -> UIDrawable | None:
"""Find the first UI element with the specified name."""
...
-
-def findAll(pattern: str, scene: Optional[str] = None) -> List[UIElement]:
- """Find all UI elements matching a name pattern (supports * wildcards)."""
+def find_all(pattern: str, scene: str = None) -> list:
+ """Find all UI elements matching a name pattern."""
...
-
-def getMetrics() -> Dict[str, Union[int, float]]:
+def get_metrics() -> dict:
"""Get current performance metrics."""
...
+def lock() -> _LockContext:
+ """Get a context manager for thread-safe UI updates from background threads."""
+ ...
+def log_benchmark(message: str) -> None:
+ """Add a log message to the current benchmark frame."""
+ ...
+def set_dev_console(enabled: bool) -> None:
+ """Enable or disable the developer console overlay."""
+ ...
+def set_scale(multiplier: float) -> None:
+ """Deprecated: use Window.resolution instead. Scale the game window size."""
+ ...
+def start_benchmark() -> None:
+ """Start capturing benchmark data to a file."""
+ ...
+def step(dt: float = None) -> float:
+ """Advance simulation time (headless mode only)."""
+ ...
-# Submodule
-class automation:
- """Automation API for testing and scripting."""
-
- @staticmethod
- def screenshot(filename: str) -> bool:
- """Save a screenshot to the specified file."""
- ...
-
- @staticmethod
- def position() -> Tuple[int, int]:
- """Get current mouse position as (x, y) tuple."""
- ...
-
- @staticmethod
- def size() -> Tuple[int, int]:
- """Get screen size as (width, height) tuple."""
- ...
-
- @staticmethod
- def onScreen(x: int, y: int) -> bool:
- """Check if coordinates are within screen bounds."""
- ...
-
- @staticmethod
- def moveTo(x: int, y: int, duration: float = 0.0) -> None:
- """Move mouse to absolute position."""
- ...
-
- @staticmethod
- def moveRel(xOffset: int, yOffset: int, duration: float = 0.0) -> None:
- """Move mouse relative to current position."""
- ...
-
- @staticmethod
- def dragTo(x: int, y: int, duration: float = 0.0, button: str = 'left') -> None:
- """Drag mouse to position."""
- ...
-
- @staticmethod
- def dragRel(xOffset: int, yOffset: int, duration: float = 0.0, button: str = 'left') -> None:
- """Drag mouse relative to current position."""
- ...
-
- @staticmethod
- def click(x: Optional[int] = None, y: Optional[int] = None, clicks: int = 1,
- interval: float = 0.0, button: str = 'left') -> None:
- """Click mouse at position."""
- ...
-
- @staticmethod
- def mouseDown(x: Optional[int] = None, y: Optional[int] = None, button: str = 'left') -> None:
- """Press mouse button down."""
- ...
-
- @staticmethod
- def mouseUp(x: Optional[int] = None, y: Optional[int] = None, button: str = 'left') -> None:
- """Release mouse button."""
- ...
-
- @staticmethod
- def keyDown(key: str) -> None:
- """Press key down."""
- ...
-
- @staticmethod
- def keyUp(key: str) -> None:
- """Release key."""
- ...
-
- @staticmethod
- def press(key: str) -> None:
- """Press and release a key."""
- ...
-
- @staticmethod
- def typewrite(text: str, interval: float = 0.0) -> None:
- """Type text with optional interval between characters."""
- ...
+# --- Module-level constants ---------------------------------------------
+default_font: Font
+default_fov: FOV
+default_texture: Texture
+keyboard: Keyboard
+mouse: Mouse
+window: Window
diff --git a/tools/generate_stubs_v2.py b/tools/generate_stubs_v2.py
index 648435b..bf7d0fe 100644
--- a/tools/generate_stubs_v2.py
+++ b/tools/generate_stubs_v2.py
@@ -1,959 +1,512 @@
#!/usr/bin/env python3
-"""Generate .pyi type stub files for McRogueFace Python API - Version 2.
+"""Generate .pyi type stub files for McRogueFace Python API.
-This script creates properly formatted type stubs by manually defining
-the API based on the documentation we've created.
+Uses runtime introspection of the compiled mcrfpy module. Signatures are
+extracted from the first line of each docstring when present, with a
+fallback to (*args, **kwargs) when a class or callable has no signature
+declared.
+
+Run via McRogueFace itself so the mcrfpy module is importable:
+
+ ./build/mcrogueface --headless --exec tools/generate_stubs_v2.py
"""
import os
-import mcrfpy
+import re
+import sys
+import types
+import inspect
+from pathlib import Path
-def generate_mcrfpy_stub():
- """Generate the main mcrfpy.pyi stub file."""
- return '''"""Type stubs for McRogueFace Python API.
+try:
+ import mcrfpy
+except ImportError:
+ print("Error: this script must be run under McRogueFace (needs mcrfpy)")
+ sys.exit(1)
-Core game engine interface for creating roguelike games with Python.
+
+# ---------- signature extraction ----------
+
+_SIG_NAME_RE = re.compile(r"^\s*(\w+)\s*\(")
+_RET_RE = re.compile(r"^\s*->\s*(.+?)\s*$")
+
+
+def _parse_balanced_signature(line):
+ """Parse 'name(...) -> ret' with proper paren/bracket depth tracking.
+
+ Returns (name, params_text, return_text) or None if not a signature.
+ Rejects multi-form signatures like 'foo(x) or foo(y)' by requiring the
+ content after the matched closing paren to be empty or '-> X'.
+ """
+ m = _SIG_NAME_RE.match(line)
+ if not m:
+ return None
+ name = m.group(1)
+ i = m.end() # position right after the opening '('
+ depth = 1
+ params_start = i
+ while i < len(line) and depth:
+ c = line[i]
+ if c in "([{":
+ depth += 1
+ elif c in ")]}":
+ depth -= 1
+ if depth == 0:
+ break
+ i += 1
+ if depth != 0:
+ return None
+ params = line[params_start:i]
+ tail = line[i + 1:].strip()
+ if not tail:
+ return name, params, None
+ rm = _RET_RE.match(tail)
+ if not rm:
+ return None # trailing 'or foo(...)' or similar, bail out
+ return name, params, rm.group(1).strip()
+
+
+def first_line(doc):
+ if not doc:
+ return ""
+ return doc.strip().split("\n", 1)[0].strip()
+
+
+def extract_signature(name, doc):
+ """Parse 'name(args) -> ret' from the first docstring line.
+
+ Returns (params_str, return_str) or (None, None) if no signature present
+ or if the signature is multi-form (e.g. 'foo(x) or foo(y)').
+ """
+ line = first_line(doc)
+ if not line:
+ return None, None
+ parsed = _parse_balanced_signature(line)
+ if parsed is None:
+ return None, None
+ sig_name, params, ret = parsed
+ if sig_name != name:
+ return None, None
+ return params.strip(), ret
+
+
+def first_description_paragraph(doc):
+ """Return the first non-empty line after a signature line, if any."""
+ if not doc:
+ return ""
+ lines = doc.strip().split("\n")
+ start = 1 if lines and _parse_balanced_signature(lines[0].strip()) else 0
+ for line in lines[start:]:
+ s = line.strip()
+ if s:
+ return s
+ return ""
+
+
+# ---------- classification ----------
+
+def is_enum_like(cls):
+ """True if this class looks like an IntEnum: int subclass with uppercase members."""
+ if not issubclass(cls, int):
+ return False
+ for name, value in cls.__dict__.items():
+ if name.isupper() and isinstance(value, cls):
+ return True
+ return False
+
+
+def enum_members(cls):
+ """Yield (name, int_value) pairs for enum-like classes."""
+ for name, value in sorted(cls.__dict__.items()):
+ if name.isupper() and isinstance(value, cls):
+ yield name, int(value)
+
+
+def is_method_like(attr):
+ return isinstance(attr, (types.BuiltinFunctionType,
+ types.BuiltinMethodType,
+ types.MethodType,
+ types.FunctionType,
+ types.MethodDescriptorType,
+ types.WrapperDescriptorType,
+ types.ClassMethodDescriptorType)) or callable(attr) and not inspect.isclass(attr)
+
+
+def is_property_descriptor(attr):
+ return isinstance(attr, (types.GetSetDescriptorType, types.MemberDescriptorType, property))
+
+
+# ---------- emitters ----------
+
+def indent(text, n=4):
+ pad = " " * n
+ return "\n".join(pad + ln if ln else ln for ln in text.split("\n"))
+
+
+def _sanitize_params(params):
+ """Rewrite param forms that are not valid Python syntax.
+
+ - Bare `...` (used in docs to mean "and more kwargs") becomes `**kwargs`.
+ - `**kwargs` already present is kept.
+ """
+ if not params:
+ return params
+ # Replace a trailing ", ..." or lone "..." with **kwargs
+ if params.strip() == "...":
+ return "**kwargs"
+ # If "..." appears as a token, replace with **kwargs
+ tokens = [t.strip() for t in params.split(",")]
+ fixed = []
+ saw_kwargs = False
+ for tok in tokens:
+ if tok == "...":
+ if not saw_kwargs:
+ fixed.append("**kwargs")
+ saw_kwargs = True
+ else:
+ if tok.startswith("**"):
+ saw_kwargs = True
+ fixed.append(tok)
+ return ", ".join(fixed)
+
+
+def emit_function(name, doc, is_method=False, is_static=False):
+ """Emit a def line for a free function or method. Always returns a str
+ ending with `: ...` plus an optional one-line docstring."""
+ params, ret = extract_signature(name, doc)
+ if params is None:
+ if is_method:
+ params = "self, *args, **kwargs"
+ else:
+ params = "*args, **kwargs"
+ else:
+ params = _sanitize_params(params)
+ if is_method and not is_static:
+ params = "self" + (", " + params if params else "")
+ ret = ret or "Any"
+
+ decorator = ("@staticmethod\n" if is_static and is_method else "")
+ summary = first_description_paragraph(doc) or first_line(doc)
+ # If the signature itself is the only line, there's nothing useful to
+ # restate. Strip a summary that exactly matches the signature.
+ sig_line = f"{name}({params.replace('self, ', '').replace('self', '')})"
+ body = f'"""{escape_docstring(summary)}"""' if summary else "..."
+ # Never add duplicate bodies
+ if body == "...":
+ return f'{decorator}def {name}({params}) -> {ret}: ...'
+ return f'{decorator}def {name}({params}) -> {ret}:\n {body}\n ...'
+
+
+def escape_docstring(text):
+ # Collapse whitespace and escape triple quotes
+ t = " ".join(text.split())
+ t = t.replace('"""', "'''")
+ if len(t) > 160:
+ t = t[:157] + "..."
+ return t
+
+
+# Recognized type words the property parser will accept.
+# Lowercase maps directly to a Python typing name. Anything else must
+# look like a class name (CapitalCase).
+_TYPE_MAPPING = {
+ "int": "int",
+ "uint": "int",
+ "float": "float",
+ "bool": "bool",
+ "str": "str",
+ "string": "str",
+ "tuple": "tuple",
+ "list": "list",
+ "dict": "dict",
+ "set": "set",
+ "frozenset": "frozenset",
+ "bytes": "bytes",
+ "any": "Any",
+ "callable": "Callable",
+ "none": "None",
+ "object": "Any",
+}
+
+
+def property_type_hint(doc):
+ """Best-effort type inference from a property docstring.
+
+ Accepts the FIRST parenthesized group whose first word is either a
+ recognized primitive type or a CapitalCase class name. Skips groups
+ like "(width, height)" or "(trigger, data)" that are argument lists
+ rather than type declarations.
+ """
+ if not doc:
+ return "Any"
+ for m in re.finditer(r"\(([^()]+)\)", doc):
+ text = m.group(1).strip()
+ first = text.split(",")[0].strip()
+ lower = first.lower()
+ if lower in _TYPE_MAPPING:
+ return _TYPE_MAPPING[lower]
+ # Class-like name (starts with capital): accept
+ if re.match(r"^[A-Z][A-Za-z0-9_]*$", first):
+ return first
+ # Union-like text "int | None" etc.
+ if "|" in first and all(
+ tok.strip().lower() in _TYPE_MAPPING or re.match(r"^[A-Z]", tok.strip())
+ for tok in first.split("|")
+ ):
+ return first
+ return "Any"
+
+
+def property_is_readonly(doc):
+ if not doc:
+ return False
+ return "read-only" in doc.lower() or "readonly" in doc.lower()
+
+
+def emit_property(name, doc):
+ t = property_type_hint(doc)
+ summary = first_description_paragraph(doc) or first_line(doc)
+ if summary:
+ return f'{name}: {t} # {escape_docstring(summary)}'
+ return f'{name}: {t}'
+
+
+# ---------- class emitter ----------
+
+# Methods inherited from object that we should never emit
+_OBJECT_ATTRS = set(dir(object))
+
+
+def iter_class_members(cls):
+ """Yield (name, attr) from cls __dict__ plus inherited members, skipping dunders
+ except __init__, and skipping plain object inheritance."""
+ seen = set()
+ # Walk mro excluding object
+ for klass in cls.__mro__:
+ if klass is object:
+ break
+ for name, attr in klass.__dict__.items():
+ if name in seen:
+ continue
+ if name.startswith("__") and name != "__init__":
+ continue
+ seen.add(name)
+ yield name, attr
+
+
+def emit_class(name, cls):
+ """Emit a `class Name:` block for a regular class or IntEnum."""
+ bases = []
+ if is_enum_like(cls):
+ bases.append("IntEnum")
+
+ header = f'class {name}({", ".join(bases)}):' if bases else f'class {name}:'
+ doc = cls.__doc__ or ""
+ summary = first_description_paragraph(doc) or first_line(doc) or f"{name} type."
+ body_lines = [f'"""{escape_docstring(summary)}"""']
+
+ if is_enum_like(cls):
+ for m_name, m_val in enum_members(cls):
+ body_lines.append(f"{m_name}: int")
+ # Enums rarely have other members we need to expose in stubs
+ return header + "\n" + indent("\n".join(body_lines))
+
+ # Regular class: emit __init__, methods, properties
+ methods = []
+ properties = []
+ seen_names = set()
+
+ def add_from(klass):
+ for attr_name, attr in iter_class_members(klass):
+ if attr_name == "__init__" or attr_name in seen_names:
+ continue
+ if is_property_descriptor(attr):
+ pdoc = attr.__doc__ if not isinstance(attr, property) else (attr.fget.__doc__ if attr.fget else "")
+ properties.append((attr_name, pdoc or ""))
+ seen_names.add(attr_name)
+ elif callable(attr):
+ if attr_name in _OBJECT_ATTRS:
+ continue
+ mdoc = attr.__doc__ or ""
+ is_static = isinstance(attr, (types.BuiltinFunctionType,
+ types.BuiltinMethodType)) and not hasattr(attr, "__self__")
+ methods.append((attr_name, mdoc, is_static))
+ seen_names.add(attr_name)
+
+ add_from(cls)
+
+ # Merge delegated methods/properties from any inner data class
+ delegate = discover_delegate(name, cls)
+ if delegate is not None:
+ add_from(delegate)
+
+ # __init__: take signature from class doc when possible
+ init_params, _ = extract_signature(name, doc)
+ if init_params is None:
+ init_body = "def __init__(self, *args, **kwargs) -> None: ..."
+ else:
+ init_body = f"def __init__(self, {init_params}) -> None: ..." if init_params else \
+ "def __init__(self) -> None: ..."
+ body_lines.append(init_body)
+
+ for pname, pdoc in sorted(properties):
+ body_lines.append(emit_property(pname, pdoc))
+
+ for mname, mdoc, is_static in sorted(methods):
+ # Skip dunders we don't have a good signature for
+ if mname.startswith("__") and mname != "__init__":
+ continue
+ body_lines.append(emit_function(mname, mdoc, is_method=True, is_static=is_static))
+
+ if len(body_lines) == 1:
+ body_lines.append("...")
+ return header + "\n" + indent("\n".join(body_lines))
+
+
+# ---------- delegation discovery ----------
+
+# Some C types expose methods on an inner "_Data" helper that dir(cls) does
+# not see because __getattr__ forwards at the instance level. We probe known
+# method names on a live instance to discover the delegate type and merge its
+# surface into the stub.
+_DELEGATION_PROBES = (
+ "center_camera", # Grid/GridView -> _GridData
+ "camera_rotation",
+ "add_collision_label",
+ "entities",
+ "compute_fov",
+ "add_layer",
+ "apply_threshold",
+)
+
+_DELEGATE_CLASS_FACTORIES = {
+ # class_name: callable returning a live instance, or None to skip
+ "Grid": lambda: mcrfpy.Grid(grid_size=(2, 2)),
+ "GridView": lambda: mcrfpy.GridView(grid=mcrfpy.Grid(grid_size=(2, 2))),
+}
+
+
+def discover_delegate(cls_name, cls):
+ """Return a delegate type if `cls` forwards known method names to it, else None."""
+ factory = _DELEGATE_CLASS_FACTORIES.get(cls_name)
+ if factory is None:
+ return None
+ try:
+ inst = factory()
+ except Exception:
+ return None
+ for probe in _DELEGATION_PROBES:
+ try:
+ m = getattr(inst, probe, None)
+ except Exception:
+ continue
+ if callable(m) and hasattr(m, "__self__"):
+ s_type = type(m.__self__)
+ if s_type is not cls:
+ return s_type
+ return None
+
+
+# ---------- submodule (automation) ----------
+
+def emit_submodule(mod_name, mod):
+ lines = [f"class _{mod_name}_module:"]
+ body = [f'"""Stub for mcrfpy.{mod_name} submodule."""']
+ for name in sorted(dir(mod)):
+ if name.startswith("_"):
+ continue
+ attr = getattr(mod, name)
+ if callable(attr):
+ body.append(emit_function(name, attr.__doc__ or "", is_method=True, is_static=True))
+ if len(body) == 1:
+ body.append("...")
+ lines.append(indent("\n".join(body)))
+ lines.append(f"{mod_name}: _{mod_name}_module")
+ return "\n".join(lines)
+
+
+# ---------- main entry ----------
+
+HEADER = '''"""Type stubs for McRogueFace Python API.
+
+Auto-generated by tools/generate_stubs_v2.py via runtime introspection.
+Do not edit by hand -- regenerate after API changes:
+
+ make && ./tools/generate_all_docs.sh
"""
-from typing import Any, List, Dict, Tuple, Optional, Callable, Union, overload
-
-# Type aliases
-UIElement = Union['Frame', 'Caption', 'Sprite', 'Grid', 'Line', 'Circle', 'Arc']
-Transition = Union[str, None]
-
-# Classes
-
-class Color:
- """SFML Color Object for RGBA colors."""
-
- r: int
- g: int
- b: int
- a: int
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, r: int, g: int, b: int, a: int = 255) -> None: ...
-
- def from_hex(self, hex_string: str) -> 'Color':
- """Create color from hex string (e.g., '#FF0000' or 'FF0000')."""
- ...
-
- def to_hex(self) -> str:
- """Convert color to hex string format."""
- ...
-
- def lerp(self, other: 'Color', t: float) -> 'Color':
- """Linear interpolation between two colors."""
- ...
-
-class Vector:
- """SFML Vector Object for 2D coordinates."""
-
- x: float
- y: float
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, x: float, y: float) -> None: ...
-
- def add(self, other: 'Vector') -> 'Vector': ...
- def subtract(self, other: 'Vector') -> 'Vector': ...
- def multiply(self, scalar: float) -> 'Vector': ...
- def divide(self, scalar: float) -> 'Vector': ...
- def distance(self, other: 'Vector') -> float: ...
- def normalize(self) -> 'Vector': ...
- def dot(self, other: 'Vector') -> float: ...
-
-class Texture:
- """SFML Texture Object for images."""
-
- def __init__(self, filename: str) -> None: ...
-
- filename: str
- width: int
- height: int
- sprite_count: int
-
-class Font:
- """SFML Font Object for text rendering."""
-
- def __init__(self, filename: str) -> None: ...
-
- filename: str
- family: str
-
-class Drawable:
- """Base class for all drawable UI elements."""
-
- x: float
- y: float
- visible: bool
- z_index: int
- name: str
- pos: Vector
-
- # Mouse event callbacks (#140, #141)
- on_click: Optional[Callable[[float, float, int, str], None]]
- on_enter: Optional[Callable[[float, float, int, str], None]]
- on_exit: Optional[Callable[[float, float, int, str], None]]
- on_move: Optional[Callable[[float, float, int, str], None]]
-
- # Read-only hover state (#140)
- hovered: bool
-
- def get_bounds(self) -> Tuple[float, float, float, float]:
- """Get bounding box as (x, y, width, height)."""
- ...
-
- def move(self, dx: float, dy: float) -> None:
- """Move by relative offset (dx, dy)."""
- ...
-
- def resize(self, width: float, height: float) -> None:
- """Resize to new dimensions (width, height)."""
- ...
-
-class Frame(Drawable):
- """Frame(x=0, y=0, w=0, h=0, fill_color=None, outline_color=None, outline=0, on_click=None, children=None)
-
- A rectangular frame UI element that can contain other drawable elements.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, x: float = 0, y: float = 0, w: float = 0, h: float = 0,
- fill_color: Optional[Color] = None, outline_color: Optional[Color] = None,
- outline: float = 0, on_click: Optional[Callable] = None,
- children: Optional[List[UIElement]] = None) -> None: ...
-
- w: float
- h: float
- fill_color: Color
- outline_color: Color
- outline: float
- on_click: Optional[Callable[[float, float, int], None]]
- children: 'UICollection'
- clip_children: bool
-
-class Caption(Drawable):
- """Caption(text='', x=0, y=0, font=None, fill_color=None, outline_color=None, outline=0, on_click=None)
-
- A text display UI element with customizable font and styling.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, text: str = '', x: float = 0, y: float = 0,
- font: Optional[Font] = None, fill_color: Optional[Color] = None,
- outline_color: Optional[Color] = None, outline: float = 0,
- on_click: Optional[Callable] = None) -> None: ...
-
- text: str
- font: Font
- fill_color: Color
- outline_color: Color
- outline: float
- on_click: Optional[Callable[[float, float, int], None]]
- w: float # Read-only, computed from text
- h: float # Read-only, computed from text
-
-class Sprite(Drawable):
- """Sprite(x=0, y=0, texture=None, sprite_index=0, scale=1.0, on_click=None)
-
- A sprite UI element that displays a texture or portion of a texture atlas.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, x: float = 0, y: float = 0, texture: Optional[Texture] = None,
- sprite_index: int = 0, scale: float = 1.0,
- on_click: Optional[Callable] = None) -> None: ...
-
- texture: Texture
- sprite_index: int
- scale: float
- on_click: Optional[Callable[[float, float, int], None]]
- w: float # Read-only, computed from texture
- h: float # Read-only, computed from texture
-
-class Grid(Drawable):
- """Grid(pos=(0,0), size=(0,0), grid_size=(2,2), texture=None, ...)
-
- A grid-based tilemap UI element for rendering tile-based levels and game worlds.
- Supports layers, FOV, pathfinding, and entity management.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, pos: Tuple[float, float] = (0, 0),
- size: Tuple[float, float] = (0, 0),
- grid_size: Tuple[int, int] = (2, 2),
- texture: Optional[Texture] = None,
- fill_color: Optional[Color] = None,
- on_click: Optional[Callable] = None,
- center_x: float = 0, center_y: float = 0, zoom: float = 1.0,
- visible: bool = True, opacity: float = 1.0,
- z_index: int = 0, name: str = '') -> None: ...
-
- # Dimensions
- grid_size: Tuple[int, int] # Read-only (grid_w, grid_h)
- grid_w: int # Read-only
- grid_h: int # Read-only
-
- # Position and size
- position: Tuple[float, float]
- size: Vector
- w: float
- h: float
-
- # Camera/viewport
- center: Vector # Viewport center point (pan position)
- center_x: float
- center_y: float
- zoom: float # Scale factor for rendering
-
- # Collections
- entities: 'EntityCollection' # Entities on this grid
- children: 'UICollection' # UI overlays (speech bubbles, effects)
- layers: List[Union['ColorLayer', 'TileLayer']] # Grid layers sorted by z_index
-
- # Appearance
- texture: Texture # Read-only
- fill_color: Color # Background fill color
-
- # Perspective/FOV
- perspective: Optional['Entity'] # Entity for FOV rendering (None = omniscient)
- perspective_enabled: bool # Whether to use perspective-based FOV
- fov: 'FOV' # FOV algorithm enum
- fov_radius: int # Default FOV radius
-
- # Cell-level mouse events
- on_cell_enter: Optional[Callable[['Vector'], None]]
- on_cell_exit: Optional[Callable[['Vector'], None]]
- on_cell_click: Optional[Callable[['Vector'], None]]
- hovered_cell: Optional[Tuple[int, int]] # Read-only
-
- def at(self, x: int, y: int) -> 'GridPoint':
- """Get grid point at tile coordinates."""
- ...
-
- def center_camera(self, pos: Optional[Tuple[float, float]] = None) -> None:
- """Center the camera on a tile coordinate."""
- ...
-
- # FOV methods
- def compute_fov(self, pos: Tuple[int, int], radius: int = 0,
- light_walls: bool = True, algorithm: Optional['FOV'] = None) -> None:
- """Compute field of view from a position."""
- ...
-
- def is_in_fov(self, pos: Tuple[int, int]) -> bool:
- """Check if a cell is in the field of view."""
- ...
-
- # Pathfinding methods
- def find_path(self, start: Union[Tuple[int, int], 'Vector', 'Entity'],
- end: Union[Tuple[int, int], 'Vector', 'Entity'],
- diagonal_cost: float = 1.41) -> Optional['AStarPath']:
- """Compute A* path between two points."""
- ...
-
- def get_dijkstra_map(self, root: Union[Tuple[int, int], 'Vector', 'Entity'],
- diagonal_cost: float = 1.41) -> 'DijkstraMap':
- """Get or create a Dijkstra distance map for a root position."""
- ...
-
- def clear_dijkstra_maps(self) -> None:
- """Clear all cached Dijkstra maps."""
- ...
-
- # Layer methods
- def add_layer(self, type: str, z_index: int = -1,
- texture: Optional[Texture] = None) -> Union['ColorLayer', 'TileLayer']:
- """Add a new layer to the grid."""
- ...
-
- def remove_layer(self, layer: Union['ColorLayer', 'TileLayer']) -> None:
- """Remove a layer from the grid."""
- ...
-
- def layer(self, z_index: int) -> Optional[Union['ColorLayer', 'TileLayer']]:
- """Get layer by z_index."""
- ...
-
- # Spatial queries
- def entities_in_radius(self, pos: Union[Tuple[float, float], 'Vector'],
- radius: float) -> List['Entity']:
- """Query entities within radius using spatial hash."""
- ...
-
- # HeightMap application
- def apply_threshold(self, source: 'HeightMap', range: Tuple[float, float],
- walkable: Optional[bool] = None,
- transparent: Optional[bool] = None) -> 'Grid':
- """Apply walkable/transparent properties where heightmap values are in range."""
- ...
-
- def apply_ranges(self, source: 'HeightMap',
- ranges: List[Tuple[Tuple[float, float], Dict[str, bool]]]) -> 'Grid':
- """Apply multiple thresholds in a single pass."""
- ...
-
-class Line(Drawable):
- """Line(start=None, end=None, thickness=1.0, color=None, on_click=None, **kwargs)
-
- A line UI element for drawing straight lines between two points.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, start: Optional[Tuple[float, float]] = None,
- end: Optional[Tuple[float, float]] = None,
- thickness: float = 1.0, color: Optional[Color] = None,
- on_click: Optional[Callable] = None) -> None: ...
-
- start: Vector
- end: Vector
- thickness: float
- color: Color
- on_click: Optional[Callable[[float, float, int], None]]
-
-class Circle(Drawable):
- """Circle(radius=0, center=None, fill_color=None, outline_color=None, outline=0, on_click=None, **kwargs)
-
- A circle UI element for drawing filled or outlined circles.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, radius: float = 0, center: Optional[Tuple[float, float]] = None,
- fill_color: Optional[Color] = None, outline_color: Optional[Color] = None,
- outline: float = 0, on_click: Optional[Callable] = None) -> None: ...
-
- radius: float
- center: Vector
- fill_color: Color
- outline_color: Color
- outline: float
- on_click: Optional[Callable[[float, float, int], None]]
-
-class Arc(Drawable):
- """Arc(center=None, radius=0, start_angle=0, end_angle=90, color=None, thickness=1, on_click=None, **kwargs)
-
- An arc UI element for drawing curved line segments.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, center: Optional[Tuple[float, float]] = None, radius: float = 0,
- start_angle: float = 0, end_angle: float = 90,
- color: Optional[Color] = None, thickness: float = 1.0,
- on_click: Optional[Callable] = None) -> None: ...
-
- center: Vector
- radius: float
- start_angle: float
- end_angle: float
- color: Color
- thickness: float
- on_click: Optional[Callable[[float, float, int], None]]
-
-class GridPoint:
- """Grid point representing a single tile's properties.
-
- Accessed via Grid.at(x, y). Controls walkability and transparency
- for pathfinding and FOV calculations.
- """
-
- walkable: bool # Whether entities can walk through this cell
- transparent: bool # Whether light/sight passes through this cell
- entities: List['Entity'] # Read-only list of entities at this cell
- grid_pos: Tuple[int, int] # Read-only (x, y) position in grid
-
-class GridPointState:
- """Per-entity visibility state for a grid cell.
-
- Tracks what an entity has seen/discovered. Accessed via entity perspective system.
- """
-
- visible: bool # Currently visible in FOV
- discovered: bool # Has been seen at least once
- point: Optional['GridPoint'] # The GridPoint at this position (None if not discovered)
-
-class ColorLayer:
- """A color overlay layer for Grid.
-
- Provides per-cell color values for tinting, fog of war, etc.
- """
-
- z_index: int
- grid: 'Grid' # Read-only parent grid
-
- def fill(self, color: Color) -> None:
- """Fill entire layer with a single color."""
- ...
-
- def set_color(self, pos: Tuple[int, int], color: Color) -> None:
- """Set color at a specific cell."""
- ...
-
- def get_color(self, pos: Tuple[int, int]) -> Color:
- """Get color at a specific cell."""
- ...
-
-class TileLayer:
- """A tile sprite layer for Grid.
-
- Provides per-cell tile indices for multi-layer tile rendering.
- """
-
- z_index: int
- grid: 'Grid' # Read-only parent grid
- texture: Optional[Texture]
-
- def fill(self, tile_index: int) -> None:
- """Fill entire layer with a single tile index."""
- ...
-
- def set_tile(self, pos: Tuple[int, int], tile_index: int) -> None:
- """Set tile index at a specific cell."""
- ...
-
- def get_tile(self, pos: Tuple[int, int]) -> int:
- """Get tile index at a specific cell."""
- ...
-
-class FOV:
- """Field of view algorithm enum.
-
- Available algorithms:
- - FOV.BASIC: Simple raycasting
- - FOV.DIAMOND: Diamond-shaped FOV
- - FOV.SHADOW: Shadow casting (recommended)
- - FOV.PERMISSIVE_0 through FOV.PERMISSIVE_8: Permissive algorithms
- - FOV.RESTRICTIVE: Restrictive precise angle shadowcasting
- """
-
- BASIC: 'FOV'
- DIAMOND: 'FOV'
- SHADOW: 'FOV'
- PERMISSIVE_0: 'FOV'
- PERMISSIVE_1: 'FOV'
- PERMISSIVE_2: 'FOV'
- PERMISSIVE_3: 'FOV'
- PERMISSIVE_4: 'FOV'
- PERMISSIVE_5: 'FOV'
- PERMISSIVE_6: 'FOV'
- PERMISSIVE_7: 'FOV'
- PERMISSIVE_8: 'FOV'
- RESTRICTIVE: 'FOV'
-
-class AStarPath:
- """A* pathfinding result.
-
- Returned by Grid.find_path(). Can be iterated or walked step-by-step.
- """
-
- def __iter__(self) -> Any: ...
- def __len__(self) -> int: ...
-
- def walk(self) -> Optional[Tuple[int, int]]:
- """Get next step in path, or None if complete."""
- ...
-
- def reverse(self) -> 'AStarPath':
- """Return a reversed copy of the path."""
- ...
-
-class DijkstraMap:
- """Dijkstra distance map for pathfinding.
-
- Created by Grid.get_dijkstra_map(). Provides distance queries
- and path finding from the root position.
- """
-
- root: Tuple[int, int] # Read-only root position
-
- def get_distance(self, pos: Tuple[int, int]) -> float:
- """Get distance from root to position (-1 if unreachable)."""
- ...
-
- def get_path(self, pos: Tuple[int, int]) -> Optional[List[Tuple[int, int]]]:
- """Get path from position to root."""
- ...
-
-class HeightMap:
- """2D height field for terrain generation.
-
- Used for procedural generation and applying terrain to grids.
- """
-
- width: int # Read-only
- height: int # Read-only
-
- def __init__(self, width: int, height: int) -> None: ...
-
- def get(self, x: int, y: int) -> float:
- """Get height value at position."""
- ...
-
- def set(self, x: int, y: int, value: float) -> None:
- """Set height value at position."""
- ...
-
- def fill(self, value: float) -> 'HeightMap':
- """Fill entire heightmap with a value."""
- ...
-
- def clear(self) -> 'HeightMap':
- """Clear heightmap to 0."""
- ...
-
- def normalize(self, min_val: float = 0.0, max_val: float = 1.0) -> 'HeightMap':
- """Normalize values to range."""
- ...
-
- def add_hill(self, center: Tuple[float, float], radius: float, height: float) -> 'HeightMap':
- """Add a hill at position."""
- ...
-
- def add_fbm(self, noise: 'NoiseSource', mulx: float = 1.0, muly: float = 1.0,
- addx: float = 0.0, addy: float = 0.0, octaves: int = 4,
- delta: float = 1.0, scale: float = 1.0) -> 'HeightMap':
- """Add fractal Brownian motion noise."""
- ...
-
- def scale(self, factor: float) -> 'HeightMap':
- """Scale all values by factor."""
- ...
-
- def clamp(self, min_val: float, max_val: float) -> 'HeightMap':
- """Clamp values to range."""
- ...
-
-class NoiseSource:
- """Coherent noise generator for procedural generation.
-
- Supports various noise types: PERLIN, SIMPLEX, WAVELET, etc.
- """
-
- def __init__(self, type: str = 'SIMPLEX', seed: Optional[int] = None) -> None: ...
-
- def get(self, x: float, y: float, z: float = 0.0) -> float:
- """Get noise value at position."""
- ...
-
-class BSP:
- """Binary space partitioning for dungeon generation.
-
- Recursively subdivides a rectangle into rooms.
- """
-
- x: int
- y: int
- width: int
- height: int
- level: int
- horizontal: bool
- position: int
-
- def __init__(self, x: int, y: int, width: int, height: int) -> None: ...
-
- def split_recursive(self, randomizer: Optional[Any] = None, nb: int = 8,
- minHSize: int = 4, minVSize: int = 4,
- maxHRatio: float = 1.5, maxVRatio: float = 1.5) -> None:
- """Recursively split the BSP tree."""
- ...
-
- def traverse(self, callback: Callable[['BSP'], bool],
- order: str = 'PRE_ORDER') -> None:
- """Traverse BSP tree calling callback for each node."""
- ...
-
- def is_leaf(self) -> bool:
- """Check if this is a leaf node (no children)."""
- ...
-
- def contains(self, x: int, y: int) -> bool:
- """Check if point is within this node's bounds."""
- ...
-
- def get_left(self) -> Optional['BSP']:
- """Get left child node."""
- ...
-
- def get_right(self) -> Optional['BSP']:
- """Get right child node."""
- ...
-
-class Entity(Drawable):
- """Entity(grid_x=0, grid_y=0, texture=None, sprite_index=0, name='')
-
- Game entity that lives within a Grid.
- """
-
- @overload
- def __init__(self) -> None: ...
- @overload
- def __init__(self, grid_x: float = 0, grid_y: float = 0, texture: Optional[Texture] = None,
- sprite_index: int = 0, name: str = '') -> None: ...
-
- grid_x: float
- grid_y: float
- texture: Texture
- sprite_index: int
- grid: Optional[Grid]
-
- def at(self, grid_x: float, grid_y: float) -> None:
- """Move entity to grid position."""
- ...
-
- def die(self) -> None:
- """Remove entity from its grid."""
- ...
-
- def index(self) -> int:
- """Get index in parent grid's entity collection."""
- ...
-
-class UICollection:
- """Collection of UI drawable elements (Frame, Caption, Sprite, Grid, Line, Circle, Arc)."""
-
- def __len__(self) -> int: ...
- def __getitem__(self, index: int) -> UIElement: ...
- def __setitem__(self, index: int, value: UIElement) -> None: ...
- def __delitem__(self, index: int) -> None: ...
- def __contains__(self, item: UIElement) -> bool: ...
- def __iter__(self) -> Any: ...
- def __add__(self, other: 'UICollection') -> 'UICollection': ...
- def __iadd__(self, other: 'UICollection') -> 'UICollection': ...
-
- def append(self, item: UIElement) -> None: ...
- def extend(self, items: List[UIElement]) -> None: ...
- def remove(self, item: UIElement) -> None: ...
- def index(self, item: UIElement) -> int: ...
- def count(self, item: UIElement) -> int: ...
-
-class EntityCollection:
- """Collection of Entity objects."""
-
- def __len__(self) -> int: ...
- def __getitem__(self, index: int) -> Entity: ...
- def __setitem__(self, index: int, value: Entity) -> None: ...
- def __delitem__(self, index: int) -> None: ...
- def __contains__(self, item: Entity) -> bool: ...
- def __iter__(self) -> Any: ...
- def __add__(self, other: 'EntityCollection') -> 'EntityCollection': ...
- def __iadd__(self, other: 'EntityCollection') -> 'EntityCollection': ...
-
- def append(self, item: Entity) -> None: ...
- def extend(self, items: List[Entity]) -> None: ...
- def remove(self, item: Entity) -> None: ...
- def index(self, item: Entity) -> int: ...
- def count(self, item: Entity) -> int: ...
-
-class Scene:
- """Base class for object-oriented scenes."""
-
- name: str
- children: UICollection # #151: UI elements collection (read-only alias for get_ui())
- on_key: Optional[Callable[[str, str], None]] # Keyboard handler (key, action)
-
- def __init__(self, name: str) -> None: ...
-
- def activate(self) -> None:
- """Called when scene becomes active."""
- ...
-
- def deactivate(self) -> None:
- """Called when scene becomes inactive."""
- ...
-
- def get_ui(self) -> UICollection:
- """Get UI elements collection."""
- ...
-
- def on_keypress(self, key: str, pressed: bool) -> None:
- """Handle keyboard events (override in subclass)."""
- ...
-
- def on_click(self, x: float, y: float, button: int) -> None:
- """Handle mouse clicks (override in subclass)."""
- ...
-
- def on_enter(self) -> None:
- """Called when entering the scene (override in subclass)."""
- ...
-
- def on_exit(self) -> None:
- """Called when leaving the scene (override in subclass)."""
- ...
-
- def on_resize(self, width: int, height: int) -> None:
- """Handle window resize events (override in subclass)."""
- ...
-
- def update(self, dt: float) -> None:
- """Update scene logic (override in subclass)."""
- ...
-
-class Timer:
- """Timer object for scheduled callbacks."""
-
- name: str
- interval: int
- active: bool
-
- def __init__(self, name: str, callback: Callable[[float], None], interval: int) -> None: ...
-
- def pause(self) -> None:
- """Pause the timer."""
- ...
-
- def resume(self) -> None:
- """Resume the timer."""
- ...
-
- def cancel(self) -> None:
- """Cancel and remove the timer."""
- ...
-
-class Window:
- """Window singleton for managing the game window."""
-
- resolution: Tuple[int, int]
- fullscreen: bool
- vsync: bool
- title: str
- fps_limit: int
- game_resolution: Tuple[int, int]
- scaling_mode: str
-
- @staticmethod
- def get() -> 'Window':
- """Get the window singleton instance."""
- ...
-
-class Animation:
- """Animation object for animating UI properties."""
-
- target: Any
- property: str
- duration: float
- easing: str
- loop: bool
- on_complete: Optional[Callable]
-
- def __init__(self, target: Any, property: str, start_value: Any, end_value: Any,
- duration: float, easing: str = 'linear', loop: bool = False,
- on_complete: Optional[Callable] = None) -> None: ...
-
- def start(self) -> None:
- """Start the animation."""
- ...
-
- def update(self, dt: float) -> bool:
- """Update animation, returns True if still running."""
- ...
-
- def get_current_value(self) -> Any:
- """Get the current interpolated value."""
- ...
-
-# Module functions
-
-def createSoundBuffer(filename: str) -> int:
- """Load a sound effect from a file and return its buffer ID."""
- ...
-
-def loadMusic(filename: str) -> None:
- """Load and immediately play background music from a file."""
- ...
-
-def setMusicVolume(volume: int) -> None:
- """Set the global music volume (0-100)."""
- ...
-
-def setSoundVolume(volume: int) -> None:
- """Set the global sound effects volume (0-100)."""
- ...
-
-def playSound(buffer_id: int) -> None:
- """Play a sound effect using a previously loaded buffer."""
- ...
-
-def getMusicVolume() -> int:
- """Get the current music volume level (0-100)."""
- ...
-
-def getSoundVolume() -> int:
- """Get the current sound effects volume level (0-100)."""
- ...
-
-def sceneUI(scene: Optional[str] = None) -> UICollection:
- """Get all UI elements for a scene."""
- ...
-
-def currentScene() -> str:
- """Get the name of the currently active scene."""
- ...
-
-def setScene(scene: str, transition: Optional[str] = None, duration: float = 0.0) -> None:
- """Switch to a different scene with optional transition effect."""
- ...
-
-def createScene(name: str) -> None:
- """Create a new empty scene."""
- ...
-
-def keypressScene(handler: Callable[[str, bool], None]) -> None:
- """Set the keyboard event handler for the current scene."""
- ...
-
-def setTimer(name: str, handler: Callable[[float], None], interval: int) -> None:
- """Create or update a recurring timer."""
- ...
-
-def delTimer(name: str) -> None:
- """Stop and remove a timer."""
- ...
-
-def exit() -> None:
- """Cleanly shut down the game engine and exit the application."""
- ...
-
-def setScale(multiplier: float) -> None:
- """Scale the game window size (deprecated - use Window.resolution)."""
- ...
-
-def find(name: str, scene: Optional[str] = None) -> Optional[UIElement]:
- """Find the first UI element with the specified name."""
- ...
-
-def findAll(pattern: str, scene: Optional[str] = None) -> List[UIElement]:
- """Find all UI elements matching a name pattern (supports * wildcards)."""
- ...
-
-def getMetrics() -> Dict[str, Union[int, float]]:
- """Get current performance metrics."""
- ...
-
-# Submodule
-class automation:
- """Automation API for testing and scripting."""
-
- @staticmethod
- def screenshot(filename: str) -> bool:
- """Save a screenshot to the specified file."""
- ...
-
- @staticmethod
- def position() -> Tuple[int, int]:
- """Get current mouse position as (x, y) tuple."""
- ...
-
- @staticmethod
- def size() -> Tuple[int, int]:
- """Get screen size as (width, height) tuple."""
- ...
-
- @staticmethod
- def onScreen(x: int, y: int) -> bool:
- """Check if coordinates are within screen bounds."""
- ...
-
- @staticmethod
- def moveTo(x: int, y: int, duration: float = 0.0) -> None:
- """Move mouse to absolute position."""
- ...
-
- @staticmethod
- def moveRel(xOffset: int, yOffset: int, duration: float = 0.0) -> None:
- """Move mouse relative to current position."""
- ...
-
- @staticmethod
- def dragTo(x: int, y: int, duration: float = 0.0, button: str = 'left') -> None:
- """Drag mouse to position."""
- ...
-
- @staticmethod
- def dragRel(xOffset: int, yOffset: int, duration: float = 0.0, button: str = 'left') -> None:
- """Drag mouse relative to current position."""
- ...
-
- @staticmethod
- def click(x: Optional[int] = None, y: Optional[int] = None, clicks: int = 1,
- interval: float = 0.0, button: str = 'left') -> None:
- """Click mouse at position."""
- ...
-
- @staticmethod
- def mouseDown(x: Optional[int] = None, y: Optional[int] = None, button: str = 'left') -> None:
- """Press mouse button down."""
- ...
-
- @staticmethod
- def mouseUp(x: Optional[int] = None, y: Optional[int] = None, button: str = 'left') -> None:
- """Release mouse button."""
- ...
-
- @staticmethod
- def keyDown(key: str) -> None:
- """Press key down."""
- ...
-
- @staticmethod
- def keyUp(key: str) -> None:
- """Release key."""
- ...
-
- @staticmethod
- def press(key: str) -> None:
- """Press and release a key."""
- ...
-
- @staticmethod
- def typewrite(text: str, interval: float = 0.0) -> None:
- """Type text with optional interval between characters."""
- ...
+from enum import IntEnum
+from typing import Any, Callable, Dict, List, Optional, Tuple, Union, overload
'''
-def main():
- """Generate type stubs."""
- print("Generating comprehensive type stubs for McRogueFace...")
-
- # Create stubs directory
- os.makedirs('stubs', exist_ok=True)
-
- # Write main stub file
- with open('stubs/mcrfpy.pyi', 'w') as f:
- f.write(generate_mcrfpy_stub())
-
- print("Generated stubs/mcrfpy.pyi")
-
- # Create py.typed marker
- with open('stubs/py.typed', 'w') as f:
- f.write('')
-
- print("Created py.typed marker")
-
- print("\nType stubs generated successfully!")
- print("\nTo use in your IDE:")
- print("1. Add the 'stubs' directory to your project")
- print("2. Most IDEs will automatically detect the .pyi files")
- print("3. For VS Code: add to python.analysis.extraPaths in settings.json")
- print("4. For PyCharm: mark 'stubs' directory as Sources Root")
-if __name__ == '__main__':
- main()
\ No newline at end of file
+def classify_module():
+ classes = {}
+ functions = {}
+ constants = {}
+ submodules = {}
+ for name in sorted(dir(mcrfpy)):
+ if name.startswith("_"):
+ continue
+ attr = getattr(mcrfpy, name)
+ if isinstance(attr, types.ModuleType):
+ submodules[name] = attr
+ elif inspect.isclass(attr):
+ classes[name] = attr
+ elif callable(attr):
+ functions[name] = attr
+ else:
+ constants[name] = attr
+ return classes, functions, constants, submodules
+
+
+def main():
+ classes, functions, constants, submodules = classify_module()
+
+ out_lines = [HEADER]
+
+ # Emit classes (enums first so forward-reference order is sensible)
+ enum_names = [n for n, c in classes.items() if is_enum_like(c)]
+ other_names = [n for n in classes if n not in enum_names]
+
+ out_lines.append("# --- Enums --------------------------------------------------------------")
+ for n in sorted(enum_names):
+ out_lines.append(emit_class(n, classes[n]))
+ out_lines.append("")
+
+ out_lines.append("# --- Classes ------------------------------------------------------------")
+ for n in sorted(other_names):
+ out_lines.append(emit_class(n, classes[n]))
+ out_lines.append("")
+
+ out_lines.append("# --- Submodules ---------------------------------------------------------")
+ for n in sorted(submodules):
+ out_lines.append(emit_submodule(n, submodules[n]))
+ out_lines.append("")
+
+ out_lines.append("# --- Module-level functions ---------------------------------------------")
+ for n in sorted(functions):
+ fn = functions[n]
+ out_lines.append(emit_function(n, fn.__doc__ or ""))
+
+ out_lines.append("")
+ out_lines.append("# --- Module-level constants ---------------------------------------------")
+ for n in sorted(constants):
+ v = constants[n]
+ t = type(v).__name__
+ out_lines.append(f"{n}: {t}")
+
+ out_text = "\n".join(out_lines).rstrip() + "\n"
+
+ stubs_dir = Path("stubs")
+ stubs_dir.mkdir(exist_ok=True)
+ (stubs_dir / "mcrfpy.pyi").write_text(out_text)
+ (stubs_dir / "py.typed").write_text("")
+
+ print(f"Wrote stubs/mcrfpy.pyi ({len(out_text)} bytes, "
+ f"{len(classes)} classes, {len(functions)} functions, "
+ f"{len(constants)} constants, {len(submodules)} submodules)")
+
+
+if __name__ == "__main__":
+ main()