Initial commit: DOOM x MATRIX System Failure text adventure
Modulares Python-Textadventure mit Kampfsystem (Stagger, Bullet Time, Glory Kills, Hacking-Skill-Checks), Hub-Raum-Navigation, prozeduralen Encountern, 3 Charakterklassen, mehreren Enden und Story-Elementen (weißer Hase, Orakel, schwarze-Katze-Deja-vu-Glitch).
This commit is contained in:
commit
46116f7f4b
25 files changed
+2594
No files matched your search
@@ -0,0 +1,109 @@
|
||||
#!/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
|
||||
Reference in new issue
Block a user