From 2086d2558158eb931bfb4f883fd1582e832097ae Mon Sep 17 00:00:00 2001 From: John McCardle Date: Sat, 18 Apr 2026 07:33:51 -0400 Subject: [PATCH] Phase 5.3: documentation regeneration + introspection-based stub generator Regenerate HTML/Markdown API reference, man page, and type stubs against current committed HEAD (post API-freeze pass #304-#308, #252 overhaul, and Phase 3/4/5.1/5.2 changes). The previous tools/generate_stubs_v2.py hand-maintained hardcoded strings, which drifted badly: stubs still contained removed module functions (setScale, findAll, getMetrics, setDevConsole), lacked new types (GridView, Behavior, Trigger, DiscreteMap, Viewport3D, Entity3D, Model3D, Billboard, NoiseSource, WangSet, LdtkProject, HeightMap, DijkstraMap, AStarPath, ColorLayer, TileLayer, etc.), and missed post-overhaul properties (tile_width/tile_height, sprite_grid, perspective_map, cell_pos, labels, turn_order, move_speed, etc.). Rewrite the generator as a runtime-introspection script mirroring generate_dynamic_docs.py's approach: - classify mcrfpy members (classes, enums, functions, constants, submodules) - parse signatures from docstring first line with proper paren-depth tracking - translate multi-form signatures (foo(x,y) or foo(pos)) to *args/**kwargs - sanitize docstring '...' placeholder params into '**kwargs' - emit IntEnum blocks for int-subclass types with uppercase members - discover delegated methods via instance probing (Grid/GridView -> _GridData) - conservative property type inference (only accept recognized primitives and CapitalCase class names in parenthesized hints) Resulting stubs/mcrfpy.pyi (2069 lines) parses as valid Python. Markdown/HTML/man-page regeneration is otherwise timestamp-only since the introspection path was already current -- the stubs were the stale artifact. --- docs/API_REFERENCE_DYNAMIC.md | 2 +- docs/api_reference_dynamic.html | 2 +- docs/mcrfpy.3 | 4 +- stubs/mcrfpy.pyi | 2914 +++++++++++++++++++++---------- tools/generate_stubs_v2.py | 1447 ++++++--------- 5 files changed, 2535 insertions(+), 1834 deletions(-) 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()