#!/usr/bin/env python3 # -*- coding: utf-8 -*- """Room-Klasse und Hub-Navigation: verbundene Raeume statt linearer Szenen.""" from doom_matrix.engine.ui import Colors, slow_print, menu, section_title from doom_matrix.engine import cheats class Room: def __init__(self, room_id, name, description, exits=None, item_ids=None, locked_by=None, on_enter=None, one_time_event=True): self.room_id = room_id self.name = name self.description = description self.exits = exits or {} # direction_label -> room_id self.item_ids = item_ids or [] # Item-IDs, die hier liegen self.locked_by = locked_by # Keycard-Farbe oder None self.on_enter = on_enter # Funktion(player, game_ctx) -> optionales Signal ("leave", room_id) oder None self.one_time_event = one_time_event self._event_triggered = False self.visited = False class Hub: """Eine Sammlung verbundener Raeume fuer einen Layer.""" def __init__(self, rooms, start_room_id): self.rooms = {r.room_id: r for r in rooms} self.current_id = start_room_id def current(self): return self.rooms[self.current_id] def explore(self, player, item_registry, game_ctx=None): """ Haupt-Loop fuer die Raum-Navigation. item_registry: dict item_id -> Item-Objekt (aus data/items.json geladen) game_ctx: beliebiges Kontext-Objekt, das an on_enter-Callbacks weitergereicht wird. Gibt zurueck, sobald ein on_enter-Callback ein Signal-Tuple ("leave", next_scene) liefert. """ while True: room = self.current() self._describe(room) if not room.visited: room.visited = True self._collect_items(room, player, item_registry) if room.on_enter and (not room.one_time_event or not room._event_triggered): room._event_triggered = True result = room.on_enter(player, game_ctx) if result is not None: return result signal = self._prompt(player, room) if signal is not None: return signal def _describe(self, room): section_title(room.name, Colors.CYAN) slow_print(room.description) def _collect_items(self, room, player, item_registry): for item_id in room.item_ids: item = item_registry.get(item_id) if item: player.inventory.add(item) slow_print(f"{Colors.GREEN}Gefunden: {item.name}{Colors.END} - {item.description}") def _prompt(self, player, room): options = [] exit_keys = list(room.exits.items()) for i, (label, _) in enumerate(exit_keys): options.append((str(i + 1), label)) options.append(("s", "Status anzeigen")) options.append(("i", "Inventar anzeigen")) choice = menu(options, "Wohin") if cheats.try_cheat(choice, player): return None if choice == "s": player.show_status() return None if choice == "i": lines = player.inventory.list_display() if lines: for line in lines: print(f" {Colors.YELLOW}{line}{Colors.END}") else: print(f" {Colors.DIM}Inventar leer.{Colors.END}") return None try: idx = int(choice) - 1 if 0 <= idx < len(exit_keys): _, target_id = exit_keys[idx] target = self.rooms.get(target_id) if target and target.locked_by and not player.inventory.has_keycard(target.locked_by): slow_print(f"\n{Colors.RED}Diese Tuer benoetigt eine {target.locked_by}e Keycard.{Colors.END}") return None self.current_id = target_id return None except ValueError: pass slow_print(f"{Colors.YELLOW}Das geht hier nicht.{Colors.END}") return None