#!/usr/bin/env python3 """Generate COMPLETE HTML API reference documentation for McRogueFace with NO missing methods.""" import os import sys import datetime import html from pathlib import Path import mcrfpy def escape_html(text: str) -> str: """Escape HTML special characters.""" return html.escape(text) if text else "" def get_complete_method_documentation(): """Return complete documentation for ALL methods across all classes.""" return { # Base Drawable methods (inherited by all UI elements) 'Drawable': { 'get_bounds': { 'signature': 'get_bounds()', 'description': 'Get the bounding rectangle of this drawable element.', 'returns': 'tuple: (x, y, width, height) representing the element\'s bounds', 'note': 'The bounds are in screen coordinates and account for current position and size.' }, 'move': { 'signature': 'move(dx, dy)', 'description': 'Move the element by a relative offset.', 'args': [ ('dx', 'float', 'Horizontal offset in pixels'), ('dy', 'float', 'Vertical offset in pixels') ], 'note': 'This modifies the x and y position properties by the given amounts.' }, 'resize': { 'signature': 'resize(width, height)', 'description': 'Resize the element to new dimensions.', 'args': [ ('width', 'float', 'New width in pixels'), ('height', 'float', 'New height in pixels') ], 'note': 'For Caption and Sprite, this may not change actual size if determined by content.' } }, # Entity-specific methods 'Entity': { 'at': { 'signature': 'at(x, y)', 'description': 'Check if this entity is at the specified grid coordinates.', 'args': [ ('x', 'int', 'Grid x coordinate to check'), ('y', 'int', 'Grid y coordinate to check') ], 'returns': 'bool: True if entity is at position (x, y), False otherwise' }, 'die': { 'signature': 'die()', 'description': 'Remove this entity from its parent grid.', 'note': 'The entity object remains valid but is no longer rendered or updated.' }, 'index': { 'signature': 'index()', 'description': 'Get the index of this entity in its parent grid\'s entity list.', 'returns': 'int: Index position, or -1 if not in a grid' } }, # Grid-specific methods 'Grid': { 'at': { 'signature': 'at(x, y)', 'description': 'Get the GridPoint at the specified grid coordinates.', 'args': [ ('x', 'int', 'Grid x coordinate'), ('y', 'int', 'Grid y coordinate') ], 'returns': 'GridPoint or None: The grid point at (x, y), or None if out of bounds' } }, # Collection methods 'EntityCollection': { 'append': { 'signature': 'append(entity)', 'description': 'Add an entity to the end of the collection.', 'args': [('entity', 'Entity', 'The entity to add')] }, 'remove': { 'signature': 'remove(entity)', 'description': 'Remove the first occurrence of an entity from the collection.', 'args': [('entity', 'Entity', 'The entity to remove')], 'raises': 'ValueError: If entity is not in collection' }, 'extend': { 'signature': 'extend(iterable)', 'description': 'Add all entities from an iterable to the collection.', 'args': [('iterable', 'Iterable[Entity]', 'Entities to add')] }, 'count': { 'signature': 'count(entity)', 'description': 'Count the number of occurrences of an entity in the collection.', 'args': [('entity', 'Entity', 'The entity to count')], 'returns': 'int: Number of times entity appears in collection' }, 'index': { 'signature': 'index(entity)', 'description': 'Find the index of the first occurrence of an entity.', 'args': [('entity', 'Entity', 'The entity to find')], 'returns': 'int: Index of entity in collection', 'raises': 'ValueError: If entity is not in collection' } }, 'UICollection': { 'append': { 'signature': 'append(drawable)', 'description': 'Add a drawable element to the end of the collection.', 'args': [('drawable', 'UIDrawable', 'The drawable element to add')] }, 'remove': { 'signature': 'remove(drawable)', 'description': 'Remove the first occurrence of a drawable from the collection.', 'args': [('drawable', 'UIDrawable', 'The drawable to remove')], 'raises': 'ValueError: If drawable is not in collection' }, 'extend': { 'signature': 'extend(iterable)', 'description': 'Add all drawables from an iterable to the collection.', 'args': [('iterable', 'Iterable[UIDrawable]', 'Drawables to add')] }, 'count': { 'signature': 'count(drawable)', 'description': 'Count the number of occurrences of a drawable in the collection.', 'args': [('drawable', 'UIDrawable', 'The drawable to count')], 'returns': 'int: Number of times drawable appears in collection' }, 'index': { 'signature': 'index(drawable)', 'description': 'Find the index of the first occurrence of a drawable.', 'args': [('drawable', 'UIDrawable', 'The drawable to find')], 'returns': 'int: Index of drawable in collection', 'raises': 'ValueError: If drawable is not in collection' } }, # Animation methods 'Animation': { 'get_current_value': { 'signature': 'get_current_value()', 'description': 'Get the current interpolated value of the animation.', 'returns': 'float: Current animation value between start and end' }, 'start': { 'signature': 'start(target)', 'description': 'Start the animation on a target UI element.', 'args': [('target', 'UIDrawable', 'The UI element to animate')], 'note': 'The target must have the property specified in the animation constructor.' }, 'update': { 'signature': 'update(delta_time)', 'description': 'Update the animation by the given time delta.', 'args': [('delta_time', 'float', 'Time elapsed since last update in seconds')], 'returns': 'bool: True if animation is still running, False if finished' } }, # Color methods 'Color': { 'from_hex': { 'signature': 'from_hex(hex_string)', 'description': 'Create a Color from a hexadecimal color string.', 'args': [('hex_string', 'str', 'Hex color string (e.g., "#FF0000" or "FF0000")')], 'returns': 'Color: New Color object from hex string', 'example': 'red = Color.from_hex("#FF0000")' }, 'to_hex': { 'signature': 'to_hex()', 'description': 'Convert this Color to a hexadecimal string.', 'returns': 'str: Hex color string in format "#RRGGBB"', 'example': 'hex_str = color.to_hex() # Returns "#FF0000"' }, 'lerp': { 'signature': 'lerp(other, t)', 'description': 'Linearly interpolate between this color and another.', 'args': [ ('other', 'Color', 'The color to interpolate towards'), ('t', 'float', 'Interpolation factor from 0.0 to 1.0') ], 'returns': 'Color: New interpolated Color object', 'example': 'mixed = red.lerp(blue, 0.5) # 50% between red and blue' } }, # Vector methods 'Vector': { 'magnitude': { 'signature': 'magnitude()', 'description': 'Calculate the length/magnitude of this vector.', 'returns': 'float: The magnitude of the vector', 'example': 'length = vector.magnitude()' }, 'magnitude_squared': { 'signature': 'magnitude_squared()', 'description': 'Calculate the squared magnitude of this vector.', 'returns': 'float: The squared magnitude (faster than magnitude())', 'note': 'Use this for comparisons to avoid expensive square root calculation.' }, 'normalize': { 'signature': 'normalize()', 'description': 'Return a unit vector in the same direction.', 'returns': 'Vector: New normalized vector with magnitude 1.0', 'raises': 'ValueError: If vector has zero magnitude' }, 'dot': { 'signature': 'dot(other)', 'description': 'Calculate the dot product with another vector.', 'args': [('other', 'Vector', 'The other vector')], 'returns': 'float: Dot product of the two vectors' }, 'distance_to': { 'signature': 'distance_to(other)', 'description': 'Calculate the distance to another vector.', 'args': [('other', 'Vector', 'The other vector')], 'returns': 'float: Distance between the two vectors' }, 'angle': { 'signature': 'angle()', 'description': 'Get the angle of this vector in radians.', 'returns': 'float: Angle in radians from positive x-axis' }, 'copy': { 'signature': 'copy()', 'description': 'Create a copy of this vector.', 'returns': 'Vector: New Vector object with same x and y values' } }, # Scene methods 'Scene': { 'activate': { 'signature': 'activate()', 'description': 'Make this scene the active scene.', 'note': 'Equivalent to calling setScene() with this scene\'s name.' }, 'get_ui': { 'signature': 'get_ui()', 'description': 'Get the UI element collection for this scene.', 'returns': 'UICollection: Collection of all UI elements in this scene' }, 'keypress': { 'signature': 'keypress(handler)', 'description': 'Register a keyboard handler function for this scene.', 'args': [('handler', 'callable', 'Function that takes (key_name: str, is_pressed: bool)')], 'note': 'Alternative to overriding the on_keypress method.' }, 'register_keyboard': { 'signature': 'register_keyboard(callable)', 'description': 'Register a keyboard event handler function for the scene.', 'args': [('callable', 'callable', 'Function that takes (key: str, action: str) parameters')], 'note': 'Alternative to overriding the on_keypress method when subclassing Scene objects.', 'example': '''def handle_keyboard(key, action): print(f"Key '{key}' was {action}") if key == "q" and action == "press": # Handle quit pass scene.register_keyboard(handle_keyboard)''' } }, # Timer methods 'Timer': { 'pause': { 'signature': 'pause()', 'description': 'Pause the timer, stopping its callback execution.', 'note': 'Use resume() to continue the timer from where it was paused.' }, 'resume': { 'signature': 'resume()', 'description': 'Resume a paused timer.', 'note': 'Has no effect if timer is not paused.' }, 'cancel': { 'signature': 'cancel()', 'description': 'Cancel the timer and remove it from the system.', 'note': 'After cancelling, the timer object cannot be reused.' }, 'restart': { 'signature': 'restart()', 'description': 'Restart the timer from the beginning.', 'note': 'Resets the timer\'s internal clock to zero.' } }, # Window methods 'Window': { 'get': { 'signature': 'get()', 'description': 'Get the Window singleton instance.', 'returns': 'Window: The singleton window object', 'note': 'This is a static method that returns the same instance every time.' }, 'center': { 'signature': 'center()', 'description': 'Center the window on the screen.', 'note': 'Only works if the window is not fullscreen.' }, 'screenshot': { 'signature': 'screenshot(filename)', 'description': 'Take a screenshot and save it to a file.', 'args': [('filename', 'str', 'Path where to save the screenshot')], 'note': 'Supports PNG, JPG, and BMP formats based on file extension.' } } } def get_complete_function_documentation(): """Return complete documentation for ALL module functions.""" return { # Scene Management 'createScene': { 'signature': 'createScene(name: str) -> None', 'description': 'Create a new empty scene with the given name.', 'args': [('name', 'str', 'Unique name for the new scene')], 'raises': 'ValueError: If a scene with this name already exists', 'note': 'The scene is created but not made active. Use setScene() to switch to it.', 'example': 'mcrfpy.createScene("game_over")' }, 'setScene': { 'signature': 'setScene(scene: str, transition: str = None, duration: float = 0.0) -> None', 'description': 'Switch to a different scene with optional transition effect.', 'args': [ ('scene', 'str', 'Name of the scene to switch to'), ('transition', 'str', 'Transition type: "fade", "slide_left", "slide_right", "slide_up", "slide_down"'), ('duration', 'float', 'Transition duration in seconds (default: 0.0 for instant)') ], 'raises': 'KeyError: If the scene doesn\'t exist', 'example': 'mcrfpy.setScene("game", "fade", 0.5)' }, 'currentScene': { 'signature': 'currentScene() -> str', 'description': 'Get the name of the currently active scene.', 'returns': 'str: Name of the current scene', 'example': 'scene_name = mcrfpy.currentScene()' }, 'sceneUI': { 'signature': 'sceneUI(scene: str = None) -> UICollection', 'description': 'Get all UI elements for a scene.', 'args': [('scene', 'str', 'Scene name. If None, uses current scene')], 'returns': 'UICollection: All UI elements in the scene', 'raises': 'KeyError: If the specified scene doesn\'t exist', 'example': 'ui_elements = mcrfpy.sceneUI("game")' }, 'keypressScene': { 'signature': 'keypressScene(handler: callable) -> None', 'description': 'Set the keyboard event handler for the current scene.', 'args': [('handler', 'callable', 'Function that receives (key_name: str, is_pressed: bool)')], 'example': '''def on_key(key, pressed): if key == "SPACE" and pressed: player.jump() mcrfpy.keypressScene(on_key)''' }, # Audio Functions 'createSoundBuffer': { 'signature': 'createSoundBuffer(filename: str) -> int', 'description': 'Load a sound effect from a file and return its buffer ID.', 'args': [('filename', 'str', 'Path to the sound file (WAV, OGG, FLAC)')], 'returns': 'int: Buffer ID for use with playSound()', 'raises': 'RuntimeError: If the file cannot be loaded', 'example': 'jump_sound = mcrfpy.createSoundBuffer("assets/jump.wav")' }, 'loadMusic': { 'signature': 'loadMusic(filename: str, loop: bool = True) -> None', 'description': 'Load and immediately play background music from a file.', 'args': [ ('filename', 'str', 'Path to the music file (WAV, OGG, FLAC)'), ('loop', 'bool', 'Whether to loop the music (default: True)') ], 'note': 'Only one music track can play at a time. Loading new music stops the current track.', 'example': 'mcrfpy.loadMusic("assets/background.ogg", True)' }, 'playSound': { 'signature': 'playSound(buffer_id: int) -> None', 'description': 'Play a sound effect using a previously loaded buffer.', 'args': [('buffer_id', 'int', 'Sound buffer ID returned by createSoundBuffer()')], 'raises': 'RuntimeError: If the buffer ID is invalid', 'example': 'mcrfpy.playSound(jump_sound)' }, 'getMusicVolume': { 'signature': 'getMusicVolume() -> int', 'description': 'Get the current music volume level.', 'returns': 'int: Current volume (0-100)', 'example': 'current_volume = mcrfpy.getMusicVolume()' }, 'getSoundVolume': { 'signature': 'getSoundVolume() -> int', 'description': 'Get the current sound effects volume level.', 'returns': 'int: Current volume (0-100)', 'example': 'current_volume = mcrfpy.getSoundVolume()' }, 'setMusicVolume': { 'signature': 'setMusicVolume(volume: int) -> None', 'description': 'Set the global music volume.', 'args': [('volume', 'int', 'Volume level from 0 (silent) to 100 (full volume)')], 'example': 'mcrfpy.setMusicVolume(50) # Set to 50% volume' }, 'setSoundVolume': { 'signature': 'setSoundVolume(volume: int) -> None', 'description': 'Set the global sound effects volume.', 'args': [('volume', 'int', 'Volume level from 0 (silent) to 100 (full volume)')], 'example': 'mcrfpy.setSoundVolume(75) # Set to 75% volume' }, # UI Utilities 'find': { 'signature': 'find(name: str, scene: str = None) -> UIDrawable | None', 'description': 'Find the first UI element with the specified name.', 'args': [ ('name', 'str', 'Exact name to search for'), ('scene', 'str', 'Scene to search in (default: current scene)') ], 'returns': 'UIDrawable or None: The found element, or None if not found', 'note': 'Searches scene UI elements and entities within grids.', 'example': 'button = mcrfpy.find("start_button")' }, 'findAll': { 'signature': 'findAll(pattern: str, scene: str = None) -> list', 'description': 'Find all UI elements matching a name pattern.', 'args': [ ('pattern', 'str', 'Name pattern with optional wildcards (* matches any characters)'), ('scene', 'str', 'Scene to search in (default: current scene)') ], 'returns': 'list: All matching UI elements and entities', 'example': 'enemies = mcrfpy.findAll("enemy_*")' }, # System Functions 'exit': { 'signature': 'exit() -> None', 'description': 'Cleanly shut down the game engine and exit the application.', 'note': 'This immediately closes the window and terminates the program.', 'example': 'mcrfpy.exit()' }, 'getMetrics': { 'signature': 'getMetrics() -> dict', 'description': 'Get current performance metrics.', 'returns': '''dict: Performance data with keys: - frame_time: Last frame duration in seconds - avg_frame_time: Average frame time - fps: Frames per second - draw_calls: Number of draw calls - ui_elements: Total UI element count - visible_elements: Visible element count - current_frame: Frame counter - runtime: Total runtime in seconds''', 'example': 'metrics = mcrfpy.getMetrics()' }, 'setTimer': { 'signature': 'setTimer(name: str, handler: callable, interval: int) -> None', 'description': 'Create or update a recurring timer.', 'args': [ ('name', 'str', 'Unique identifier for the timer'), ('handler', 'callable', 'Function called with (runtime: float) parameter'), ('interval', 'int', 'Time between calls in milliseconds') ], 'note': 'If a timer with this name exists, it will be replaced.', 'example': '''def update_score(runtime): score += 1 mcrfpy.setTimer("score_update", update_score, 1000)''' }, 'delTimer': { 'signature': 'delTimer(name: str) -> None', 'description': 'Stop and remove a timer.', 'args': [('name', 'str', 'Timer identifier to remove')], 'note': 'No error is raised if the timer doesn\'t exist.', 'example': 'mcrfpy.delTimer("score_update")' }, 'setScale': { 'signature': 'setScale(multiplier: float) -> None', 'description': 'Scale the game window size.', 'args': [('multiplier', 'float', 'Scale factor (e.g., 2.0 for double size)')], 'note': 'The internal resolution remains 1024x768, but the window is scaled.', 'example': 'mcrfpy.setScale(2.0) # Double the window size' } } def get_complete_property_documentation(): """Return complete documentation for ALL properties.""" return { 'Animation': { 'property': 'str: Name of the property being animated (e.g., "x", "y", "scale")', 'duration': 'float: Total duration of the animation in seconds', 'elapsed_time': 'float: Time elapsed since animation started (read-only)', 'current_value': 'float: Current interpolated value of the animation (read-only)', 'is_running': 'bool: True if animation is currently running (read-only)', 'is_finished': 'bool: True if animation has completed (read-only)' }, 'GridPoint': { 'x': 'int: Grid x coordinate of this point', 'y': 'int: Grid y coordinate of this point', 'texture_index': 'int: Index of the texture/sprite to display at this point', 'solid': 'bool: Whether this point blocks movement', 'transparent': 'bool: Whether this point allows light/vision through', 'color': 'Color: Color tint applied to the texture at this point' }, 'GridPointState': { 'visible': 'bool: Whether this point is currently visible to the player', 'discovered': 'bool: Whether this point has been discovered/explored', 'custom_flags': 'int: Bitfield for custom game-specific flags' } } def generate_complete_html_documentation(): """Generate complete HTML documentation with NO missing methods.""" # Get all documentation data method_docs = get_complete_method_documentation() function_docs = get_complete_function_documentation() property_docs = get_complete_property_documentation() html_parts = [] # HTML header with enhanced styling html_parts.append('''
Generated on {datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S")}
') # Table of contents html_parts.append('The mcrfpy.automation
module provides testing and automation capabilities.
automation.{name}
{escape_html(doc_parts[1])}
') else: html_parts.append(f'{escape_html(obj.__doc__)}
') html_parts.append('{func_doc["signature"]}
{escape_html(func_doc["description"])}
') # Arguments if 'args' in func_doc: html_parts.append('')
html_parts.append(escape_html(func_doc['example']))
html_parts.append('
')
html_parts.append('{escape_html(cls.__doc__)}
') # Properties if class_name in property_docs: html_parts.append('{method_doc["signature"]}
{escape_html(method_doc["description"])}
') # Arguments if 'args' in method_doc: for arg in method_doc['args']: html_parts.append(f'')
html_parts.append(escape_html(method_doc['example']))
html_parts.append('
')
html_parts.append('