"""Verify code snippets from Phase D wiki page updates.""" import mcrfpy import sys passes = 0 fails = 0 def check(name, fn): global passes, fails try: fn() passes += 1 print(f" [OK] {name}") except Exception as e: fails += 1 print(f" [FAIL] {name}: {e}") # =================================================================== print("=== GRID INTERACTION PATTERNS ===") # =================================================================== def test_gip_setup(): """Setup template from Grid Interaction Patterns""" scene = mcrfpy.Scene("gip_test") ui = scene.children texture = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) terrain = mcrfpy.TileLayer(name="terrain", z_index=-2, texture=texture) highlight = mcrfpy.ColorLayer(name="highlight", z_index=-1) overlay = mcrfpy.ColorLayer(name="overlay", z_index=1) grid = mcrfpy.Grid( grid_size=(20, 15), pos=(50, 50), size=(640, 480), layers=[terrain, highlight, overlay] ) grid.fill_color = mcrfpy.Color(20, 20, 30) ui.append(grid) player = mcrfpy.Entity(grid_pos=(10, 7), sprite_index=0) grid.entities.append(player) mcrfpy.current_scene = scene check("GIP: setup template", test_gip_setup) def test_gip_cell_hover(): """Cell hover highlighting pattern""" grid = mcrfpy.Grid(grid_size=(20, 15), pos=(0, 0), size=(320, 240), layers=[]) highlight = mcrfpy.ColorLayer(name="highlight", z_index=-1) grid.add_layer(highlight) current_highlight = [None] def on_cell_enter(cell_pos): x, y = int(cell_pos.x), int(cell_pos.y) highlight.set((x, y), mcrfpy.Color(255, 255, 255, 40)) current_highlight[0] = (x, y) def on_cell_exit(cell_pos): x, y = int(cell_pos.x), int(cell_pos.y) highlight.set((x, y), mcrfpy.Color(0, 0, 0, 0)) current_highlight[0] = None grid.on_cell_enter = on_cell_enter grid.on_cell_exit = on_cell_exit check("GIP: cell hover highlighting", test_gip_cell_hover) def test_gip_cell_click(): """Cell click actions pattern""" grid = mcrfpy.Grid(grid_size=(20, 15), pos=(0, 0), size=(320, 240)) for x in range(20): for y in range(15): grid.at(x, y).walkable = True player = mcrfpy.Entity(grid_pos=(10, 7), sprite_index=0) grid.entities.append(player) def on_cell_click(cell_pos, button, action): x, y = int(cell_pos.x), int(cell_pos.y) point = grid.at(x, y) if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.PRESSED: if point.walkable: player.grid_x = x player.grid_y = y elif button == mcrfpy.MouseButton.RIGHT and action == mcrfpy.InputState.PRESSED: pass # inspect elif button == mcrfpy.MouseButton.MIDDLE and action == mcrfpy.InputState.PRESSED: point.walkable = not point.walkable grid.on_cell_click = on_cell_click check("GIP: cell click actions", test_gip_cell_click) def test_gip_wasd(): """WASD movement pattern""" scene = mcrfpy.Scene("gip_wasd") grid = mcrfpy.Grid(grid_size=(20, 15), pos=(0, 0), size=(320, 240)) for x in range(20): for y in range(15): grid.at(x, y).walkable = True player = mcrfpy.Entity(grid_pos=(10, 7), sprite_index=0) grid.entities.append(player) move_map = { mcrfpy.Key.W: (0, -1), mcrfpy.Key.A: (-1, 0), mcrfpy.Key.S: (0, 1), mcrfpy.Key.D: (1, 0), } def handle_key(key, action): if action != mcrfpy.InputState.PRESSED: return if key in move_map: dx, dy = move_map[key] new_x = int(player.grid_x + dx) new_y = int(player.grid_y + dy) point = player.grid.at(new_x, new_y) if point and point.walkable: player.grid_x = new_x player.grid_y = new_y scene.on_key = handle_key check("GIP: WASD movement", test_gip_wasd) def test_gip_entity_selection(): """Entity selection pattern""" grid = mcrfpy.Grid(grid_size=(20, 15), pos=(0, 0), size=(320, 240), layers=[]) overlay = mcrfpy.ColorLayer(name="overlay", z_index=1) grid.add_layer(overlay) e1 = mcrfpy.Entity(grid_pos=(5, 5), sprite_index=0, name="sel_e1") e2 = mcrfpy.Entity(grid_pos=(10, 10), sprite_index=1, name="sel_e2") grid.entities.append(e1) grid.entities.append(e2) selected = [None] def select_entity(entity): if selected[0]: ex, ey = int(selected[0].grid_x), int(selected[0].grid_y) overlay.set((ex, ey), mcrfpy.Color(0, 0, 0, 0)) selected[0] = entity if entity: overlay.set((int(entity.grid_x), int(entity.grid_y)), mcrfpy.Color(255, 200, 0, 80)) def on_cell_click(cell_pos, button, action): if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.PRESSED: x, y = int(cell_pos.x), int(cell_pos.y) for entity in grid.entities: if int(entity.grid_x) == x and int(entity.grid_y) == y: select_entity(entity) return select_entity(None) grid.on_cell_click = on_cell_click select_entity(e1) assert selected[0] == e1 check("GIP: entity selection", test_gip_entity_selection) def test_gip_path_preview(): """Path preview pattern""" grid = mcrfpy.Grid(grid_size=(20, 15), pos=(0, 0), size=(320, 240), layers=[]) highlight = mcrfpy.ColorLayer(name="highlight", z_index=-1) grid.add_layer(highlight) for x in range(20): for y in range(15): grid.at(x, y).walkable = True player = mcrfpy.Entity(grid_pos=(5, 5), sprite_index=0) grid.entities.append(player) def show_path_to(target_x, target_y): path = grid.find_path( (int(player.grid_x), int(player.grid_y)), (target_x, target_y) ) if path: while len(path) > 0: step = path.walk() if step: highlight.set((int(step.x), int(step.y)), mcrfpy.Color(100, 200, 255, 60)) show_path_to(15, 10) check("GIP: path preview", test_gip_path_preview) def test_gip_tile_inspector(): """Tile inspector panel pattern""" scene = mcrfpy.Scene("gip_inspect") ui = scene.children grid = mcrfpy.Grid(grid_size=(20, 15), pos=(0, 0), size=(320, 240)) ui.append(grid) inspector = mcrfpy.Frame(pos=(400, 50), size=(200, 150), fill_color=mcrfpy.Color(30, 30, 40, 230)) inspector.visible = False ui.append(inspector) title = mcrfpy.Caption(text="Cell Info", pos=(10, 8)) inspector.children.append(title) info = mcrfpy.Caption(text="", pos=(10, 30)) inspector.children.append(info) def on_cell_click(cell_pos, button, action): if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.PRESSED: x, y = int(cell_pos.x), int(cell_pos.y) point = grid.at(x, y) title.text = f"Cell ({x}, {y})" info.text = f"Walkable: {point.walkable}" inspector.visible = True grid.on_cell_click = on_cell_click check("GIP: tile inspector panel", test_gip_tile_inspector) # =================================================================== print("\n=== UI WIDGET PATTERNS ===") # =================================================================== def test_uwp_setup(): """Setup template""" scene = mcrfpy.Scene("uwp_test") ui = scene.children root = mcrfpy.Frame(pos=(50, 50), size=(300, 400), fill_color=mcrfpy.Color(30, 30, 40)) root.outline_color = mcrfpy.Color(80, 80, 100) root.outline = 2 ui.append(root) mcrfpy.current_scene = scene check("UWP: setup template", test_uwp_setup) def test_uwp_button(): """Button pattern""" root = mcrfpy.Frame(pos=(0, 0), size=(300, 400)) def make_button(parent, pos, text, on_click): btn = mcrfpy.Frame(pos=pos, size=(120, 32), fill_color=mcrfpy.Color(60, 60, 80)) btn.outline_color = mcrfpy.Color(100, 100, 140) btn.outline = 1 label = mcrfpy.Caption(text=text, pos=(10, 6)) label.fill_color = mcrfpy.Color(220, 220, 220) btn.children.append(label) btn.on_enter = lambda pos: setattr(btn, 'fill_color', mcrfpy.Color(80, 80, 110)) btn.on_exit = lambda pos: setattr(btn, 'fill_color', mcrfpy.Color(60, 60, 80)) btn.on_click = lambda pos, button, action: on_click() if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.PRESSED else None parent.children.append(btn) return btn b1 = make_button(root, (20, 20), "New Game", lambda: None) b2 = make_button(root, (20, 60), "Options", lambda: None) assert b1.w == 120 check("UWP: button pattern", test_uwp_button) def test_uwp_toggle(): """Toggle/checkbox pattern""" root = mcrfpy.Frame(pos=(0, 0), size=(300, 400)) def make_toggle(parent, pos, label_text, initial=False, on_change=None): state = {"checked": initial} frame = mcrfpy.Frame(pos=pos, size=(160, 28), fill_color=mcrfpy.Color(40, 40, 50)) indicator = mcrfpy.Frame(pos=(6, 6), size=(16, 16)) indicator.outline = 1 indicator.outline_color = mcrfpy.Color(120, 120, 140) frame.children.append(indicator) label = mcrfpy.Caption(text=label_text, pos=(30, 5)) label.fill_color = mcrfpy.Color(200, 200, 200) frame.children.append(label) def update_visual(): if state["checked"]: indicator.fill_color = mcrfpy.Color(100, 180, 100) else: indicator.fill_color = mcrfpy.Color(50, 50, 60) def toggle(pos, button, action): if button == mcrfpy.MouseButton.LEFT and action == mcrfpy.InputState.PRESSED: state["checked"] = not state["checked"] update_visual() if on_change: on_change(state["checked"]) frame.on_click = toggle update_visual() parent.children.append(frame) return state t = make_toggle(root, (20, 20), "Music", initial=True) assert t["checked"] == True check("UWP: toggle pattern", test_uwp_toggle) def test_uwp_vertical_menu(): """Vertical menu with keyboard nav""" scene = mcrfpy.Scene("uwp_menu") root = mcrfpy.Frame(pos=(0, 0), size=(300, 400)) scene.children.append(root) class VerticalMenu: def __init__(self, parent, pos, options, on_select): self.options = options self.on_select = on_select self.selected = 0 self.frame = mcrfpy.Frame(pos=pos, size=(180, len(options) * 28 + 8), fill_color=mcrfpy.Color(35, 35, 45)) parent.children.append(self.frame) self.items = [] for i, (label, value) in enumerate(options): item = mcrfpy.Caption(text=label, pos=(12, 4 + i * 28)) item.fill_color = mcrfpy.Color(180, 180, 180) self.frame.children.append(item) self.items.append(item) self._update_highlight() def _update_highlight(self): for i, item in enumerate(self.items): if i == self.selected: item.fill_color = mcrfpy.Color(255, 220, 100) else: item.fill_color = mcrfpy.Color(180, 180, 180) def move_up(self): self.selected = (self.selected - 1) % len(self.options) self._update_highlight() def move_down(self): self.selected = (self.selected + 1) % len(self.options) self._update_highlight() def confirm(self): _, value = self.options[self.selected] self.on_select(value) result = [None] menu = VerticalMenu(root, (20, 20), [ ("Continue", "continue"), ("New Game", "new"), ("Quit", "quit") ], on_select=lambda v: result.__setitem__(0, v)) def handle_key(key, action): if action != mcrfpy.InputState.PRESSED: return if key == mcrfpy.Key.UP: menu.move_up() elif key == mcrfpy.Key.DOWN: menu.move_down() elif key == mcrfpy.Key.ENTER: menu.confirm() scene.on_key = handle_key menu.confirm() assert result[0] == "continue" check("UWP: vertical menu", test_uwp_vertical_menu) def test_uwp_modal(): """Modal dialog pattern""" scene = mcrfpy.Scene("uwp_modal") ui = scene.children dismissed = [False] backdrop = mcrfpy.Frame(pos=(0, 0), size=(1024, 768), fill_color=mcrfpy.Color(0, 0, 0, 160)) backdrop.z_index = 900 backdrop.on_click = lambda pos, btn, action: None # Block clicks ui.append(backdrop) dialog = mcrfpy.Frame(pos=(312, 284), size=(400, 200), fill_color=mcrfpy.Color(50, 50, 65)) dialog.outline_color = mcrfpy.Color(120, 120, 150) dialog.outline = 2 dialog.z_index = 901 ui.append(dialog) msg = mcrfpy.Caption(text="Game saved!", pos=(20, 20)) msg.fill_color = mcrfpy.Color(220, 220, 220) dialog.children.append(msg) ok_btn = mcrfpy.Frame(pos=(150, 140), size=(100, 36), fill_color=mcrfpy.Color(70, 100, 70)) ok_btn.outline = 1 ok_btn.on_click = lambda pos, btn, action: dismissed.__setitem__(0, True) dialog.children.append(ok_btn) ok_label = mcrfpy.Caption(text="OK", pos=(35, 8)) ok_label.fill_color = mcrfpy.Color(220, 255, 220) ok_btn.children.append(ok_label) check("UWP: modal dialog", test_uwp_modal) def test_uwp_hotbar(): """Hotbar / quick slots pattern""" scene = mcrfpy.Scene("uwp_hotbar") root = mcrfpy.Frame(pos=(0, 0), size=(800, 600)) scene.children.append(root) slot_count = 9 slots = [] hotbar_frame = mcrfpy.Frame(pos=(200, 500), size=(slot_count * 36 + 8, 44), fill_color=mcrfpy.Color(30, 30, 40, 200)) root.children.append(hotbar_frame) for i in range(slot_count): slot = mcrfpy.Frame(pos=(4 + i * 36, 4), size=(32, 32), fill_color=mcrfpy.Color(50, 50, 60)) slot.outline = 1 slot.outline_color = mcrfpy.Color(80, 80, 100) hotbar_frame.children.append(slot) num = mcrfpy.Caption(text=str((i + 1) % 10), pos=(2, 2)) num.fill_color = mcrfpy.Color(100, 100, 120) slot.children.append(num) slots.append(slot) selected = [0] def select_slot(index): if 0 <= index < len(slots): slots[selected[0]].outline_color = mcrfpy.Color(80, 80, 100) slots[selected[0]].outline = 1 selected[0] = index slots[index].outline_color = mcrfpy.Color(200, 180, 80) slots[index].outline = 2 select_slot(0) def handle_key(key, action): if action != mcrfpy.InputState.PRESSED: return num_keys = { mcrfpy.Key.NUM_1: 0, mcrfpy.Key.NUM_2: 1, mcrfpy.Key.NUM_3: 2, mcrfpy.Key.NUM_4: 3, mcrfpy.Key.NUM_5: 4, mcrfpy.Key.NUM_6: 5, mcrfpy.Key.NUM_7: 6, mcrfpy.Key.NUM_8: 7, mcrfpy.Key.NUM_9: 8, } if key in num_keys: select_slot(num_keys[key]) scene.on_key = handle_key assert slots[0].outline == 2 check("UWP: hotbar/quick slots", test_uwp_hotbar) def test_uwp_draggable(): """Draggable window pattern""" root = mcrfpy.Frame(pos=(0, 0), size=(800, 600)) frame = mcrfpy.Frame(pos=(100, 100), size=(250, 300), fill_color=mcrfpy.Color(45, 45, 55)) frame.outline = 1 frame.outline_color = mcrfpy.Color(100, 100, 120) root.children.append(frame) title_bar = mcrfpy.Frame(pos=(0, 0), size=(250, 24), fill_color=mcrfpy.Color(60, 60, 80)) frame.children.append(title_bar) title_label = mcrfpy.Caption(text="Inventory", pos=(8, 4)) title_label.fill_color = mcrfpy.Color(200, 200, 220) title_bar.children.append(title_label) content = mcrfpy.Caption(text="Items here...", pos=(10, 38)) frame.children.append(content) check("UWP: draggable window", test_uwp_draggable) # =================================================================== print("\n=== RENDERING AND VISUALS ===") # =================================================================== def test_rv_basic_elements(): """Creating basic UI elements""" scene = mcrfpy.Scene("rv_test") ui = scene.children frame = mcrfpy.Frame(pos=(100, 100), size=(200, 150), fill_color=mcrfpy.Color(50, 50, 50)) frame.outline_color = mcrfpy.Color(255, 255, 255) frame.outline = 2 ui.append(frame) label = mcrfpy.Caption(text="Hello World!", pos=(10, 10)) label.font_size = 24 label.fill_color = mcrfpy.Color(255, 255, 255) ui.append(label) sprite = mcrfpy.Sprite(x=50, y=50, sprite_index=0) ui.append(sprite) check("RV: basic UI elements", test_rv_basic_elements) def test_rv_textures(): """Texture loading and sprite sheets""" texture = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) sprite = mcrfpy.Sprite(x=100, y=100) sprite.texture = texture sprite.sprite_index = 5 check("RV: textures and sprite sheets", test_rv_textures) def test_rv_z_order(): """Z-order layering""" scene = mcrfpy.Scene("rv_z") ui = scene.children background = mcrfpy.Frame(pos=(0, 0), size=(800, 600), fill_color=mcrfpy.Color(20, 20, 20)) background.z_index = 0 ui.append(background) grid = mcrfpy.Grid(grid_size=(20, 15), pos=(50, 50), size=(400, 300)) grid.z_index = 10 ui.append(grid) hud = mcrfpy.Frame(pos=(0, 0), size=(800, 50), fill_color=mcrfpy.Color(30, 30, 30, 200)) hud.z_index = 100 ui.append(hud) check("RV: z-order layering", test_rv_z_order) def test_rv_colors(): """Color creation and application""" red = mcrfpy.Color(255, 0, 0) semi_transparent = mcrfpy.Color(255, 255, 255, 128) frame = mcrfpy.Frame(pos=(0, 0), size=(100, 100)) frame.fill_color = mcrfpy.Color(50, 50, 50) frame.outline_color = mcrfpy.Color(255, 255, 255) caption = mcrfpy.Caption(text="Test", pos=(0, 0)) caption.fill_color = mcrfpy.Color(255, 255, 0) assert red.r == 255 assert semi_transparent.a == 128 check("RV: colors", test_rv_colors) def test_rv_animations(): """Animation patterns""" frame = mcrfpy.Frame(pos=(0, 0), size=(100, 100)) frame.animate("opacity", 1.0, 1.0, mcrfpy.Easing.EASE_IN_QUAD) frame.animate("fill_color", (255, 0, 0, 255), 0.5, mcrfpy.Easing.LINEAR) frame.animate("x", 200.0, 0.3, mcrfpy.Easing.EASE_OUT_CUBIC) check("RV: animations", test_rv_animations) def test_rv_visibility(): """Visibility control""" sprite = mcrfpy.Sprite(x=0, y=0, sprite_index=0) sprite.visible = False sprite.visible = True sprite.opacity = 0.5 assert sprite.opacity == 0.5 check("RV: visibility", test_rv_visibility) def test_rv_hud(): """HUD overlay pattern""" scene = mcrfpy.Scene("rv_hud") ui = scene.children hud = mcrfpy.Frame(pos=(0, 0), size=(800, 60), fill_color=mcrfpy.Color(30, 30, 30, 200)) hud.z_index = 100 ui.append(hud) health_label = mcrfpy.Caption(text="HP: 100/100", pos=(10, 10)) health_label.font_size = 18 health_label.fill_color = mcrfpy.Color(255, 255, 255) hud.children.append(health_label) def update_hud(current_hp, max_hp): health_label.text = f"HP: {current_hp}/{max_hp}" if current_hp < max_hp * 0.3: health_label.fill_color = mcrfpy.Color(255, 0, 0) elif current_hp < max_hp * 0.6: health_label.fill_color = mcrfpy.Color(255, 255, 0) else: health_label.fill_color = mcrfpy.Color(0, 255, 0) update_hud(50, 100) assert health_label.text == "HP: 50/100" check("RV: HUD overlay", test_rv_hud) def test_rv_health_bar(): """Health bar pattern""" bg = mcrfpy.Frame(pos=(10, 10), size=(100, 10), fill_color=mcrfpy.Color(255, 0, 0)) bg.z_index = 90 fg = mcrfpy.Frame(pos=(10, 10), size=(100, 10), fill_color=mcrfpy.Color(0, 255, 0)) fg.z_index = 91 ratio = 0.5 target_width = int(100 * ratio) fg.animate("w", float(target_width), 0.2, mcrfpy.Easing.EASE_OUT_QUAD) check("RV: health bar", test_rv_health_bar) def test_rv_grid_rendering(): """Grid rendering basics""" texture = mcrfpy.Texture("assets/kenney_tinydungeon.png", 16, 16) terrain = mcrfpy.TileLayer(name="terrain", z_index=-1, texture=texture) grid = mcrfpy.Grid(grid_size=(20, 15), pos=(100, 100), size=(400, 300), layers=[terrain]) for x in range(20): for y in range(15): if x == 0 or x == 19 or y == 0 or y == 14: terrain.set((x, y), 1) else: terrain.set((x, y), 0) check("RV: grid rendering", test_rv_grid_rendering) def test_rv_camera(): """Camera/viewport control""" grid = mcrfpy.Grid(grid_size=(50, 50), pos=(0, 0), size=(400, 400)) grid.zoom = 2.0 grid.center_camera((25, 25)) grid.animate("zoom", 1.5, 1.0, mcrfpy.Easing.EASE_IN_OUT) check("RV: camera control", test_rv_camera) def test_rv_particle_pattern(): """Particle-like effects pattern""" scene = mcrfpy.Scene("rv_particles") ui = scene.children import random def create_explosion(x, y): particles = [] for i in range(5): p = mcrfpy.Frame(pos=(x, y), size=(4, 4), fill_color=mcrfpy.Color(255, 200, 50)) p.z_index = 50 target_x = x + random.randint(-50, 50) target_y = y + random.randint(-50, 50) p.animate("x", float(target_x), 0.5, mcrfpy.Easing.EASE_OUT_QUAD) p.animate("y", float(target_y), 0.5, mcrfpy.Easing.EASE_OUT_QUAD) p.animate("opacity", 0.0, 0.5, mcrfpy.Easing.LINEAR) particles.append(p) ui.append(p) return particles particles = create_explosion(100, 100) assert len(particles) == 5 check("RV: particle effects", test_rv_particle_pattern) # =================================================================== print("\n" + "=" * 60) print(f"PHASE D VERIFICATION: {passes} passed, {fails} failed") print("=" * 60) if fails: sys.exit(1) else: sys.exit(0)