Files
fedora_openclaw 46116f7f4b 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).
2026-07-05 18:56:44 +02:00

233 lines
8.5 KiB
Python

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""Player-Klasse: Stats, Klassen, Leveling, Inventar, Story-Flags."""
import json
import os
from doom_matrix.engine.ui import Colors, bar
from doom_matrix.entities.items import Inventory, Weapon
_WEAPON_DATA_PATH = os.path.join(os.path.dirname(os.path.dirname(__file__)), "data", "weapons.json")
_WEAPON_TEMPLATES = None
def _load_weapon_templates():
global _WEAPON_TEMPLATES
if _WEAPON_TEMPLATES is None:
with open(_WEAPON_DATA_PATH, "r", encoding="utf-8") as f:
data = json.load(f)
_WEAPON_TEMPLATES = {d["id"]: d for d in data}
return _WEAPON_TEMPLATES
def make_weapon(weapon_id):
templates = _load_weapon_templates()
return Weapon.from_dict(templates[weapon_id])
# Charakterklassen: Basiswerte
CLASSES = {
"slayer": {
"name": "Slayer",
"description": "Doom-Fokus. Mehr HP und Staerke, schwaecheres Hacking.",
"hp": 120, "armor": 20, "focus": 60, "hacking": 2, "strength": 8, "corruption_rate": 1.0,
"start_weapon": "super_shotgun", "start_ammo": {"shells": 20},
},
"operator": {
"name": "Operator",
"description": "Matrix-Fokus. Starkes Hacking und Focus, koerperlich schwaecher.",
"hp": 85, "armor": 10, "focus": 100, "hacking": 9, "strength": 3, "corruption_rate": 1.0,
"start_weapon": "plasma_rifle", "start_ammo": {"cells": 100},
},
"hybrid": {
"name": "Anomalie",
"description": "Ausgewogen. Einzigartige Dialogoptionen, aber doppelte Corruption.",
"hp": 100, "armor": 15, "focus": 80, "hacking": 5, "strength": 5, "corruption_rate": 2.0,
"start_weapon": "super_shotgun", "start_ammo": {"shells": 10, "cells": 40},
},
}
class Player:
def __init__(self, player_class="slayer"):
cls_data = CLASSES[player_class]
self.player_class = player_class
self.class_name = cls_data["name"]
self.name = "The One Slayer"
self.max_health = cls_data["hp"]
self.health = cls_data["hp"]
self.armor = cls_data["armor"]
self.max_focus = cls_data["focus"]
self.focus = cls_data["focus"]
self.hacking = cls_data["hacking"]
self.strength = cls_data["strength"]
self.corruption_rate = cls_data["corruption_rate"]
self.corruption = 0 # 0-100
self.level = 1
self.praetor_tokens = 0
self.weapons = [make_weapon("fists")]
start_weapon = make_weapon(cls_data["start_weapon"])
self.weapons.append(start_weapon)
self.ammo = {"bullets": 0, "shells": 0, "cells": 0, "bfg": 0}
self.ammo.update(cls_data["start_ammo"])
self.inventory = Inventory()
self.layer = 3 # Start in Matrix
self.location = "construct"
self.glory_kills = 0
self.hacks = 0
self.trace_marks = 0
# Story-Flags fuer Easter Eggs / Verzweigungen
self.flags = {
"met_oracle": False,
"saw_rabbit": False,
"cat_glitch_count": 0,
"cat_glitch_seen": False,
"god_mode": False,
"cheats_used": [],
}
def has_weapon(self, weapon_id):
return any(w.weapon_id == weapon_id for w in self.weapons)
def get_weapon(self, weapon_id):
for w in self.weapons:
if w.weapon_id == weapon_id:
return w
return None
def add_weapon(self, weapon_id):
if not self.has_weapon(weapon_id):
self.weapons.append(make_weapon(weapon_id))
def heal(self, amount):
self.health = min(self.max_health, self.health + amount)
def take_damage(self, amount):
"""Wendet Schaden an, Armor absorbiert zuerst. Gibt (final_damage, armor_absorbed) zurueck."""
if self.flags.get("god_mode"):
return 0, 0
armor_absorb = min(self.armor, amount)
self.armor -= armor_absorb
remaining = amount - armor_absorb
self.health = max(0, self.health - remaining)
return remaining, armor_absorb
def add_armor(self, amount):
self.armor = min(100, self.armor + amount)
def gain_corruption(self, amount):
self.corruption = min(100, self.corruption + amount * self.corruption_rate)
def is_dead(self):
return self.health <= 0
def try_auto_revive(self):
if self.inventory.has_backup_pill and self.is_dead():
self.inventory.has_backup_pill = False
self.health = int(self.max_health * 0.5)
return True
return False
def spend_praetor_token(self, stat):
if self.praetor_tokens <= 0:
return False
self.praetor_tokens -= 1
if stat == "health":
self.max_health += 15
self.health = min(self.max_health, self.health + 15)
elif stat == "focus":
self.max_focus += 15
self.focus = min(self.max_focus, self.focus + 15)
elif stat == "hacking":
self.hacking += 2
elif stat == "strength":
self.strength += 2
return True
def _layer_name(self):
layers = {
4: f"{Colors.RED}MARS UAC BASE{Colors.END}",
3: f"{Colors.GREEN}THE MATRIX{Colors.END}",
2: f"{Colors.MAGENTA}HELL SERVER{Colors.END}",
1: f"{Colors.YELLOW}THE ARCHITECT'S CORE{Colors.END}",
0: f"{Colors.WHITE}{Colors.BOLD}LAYER 0{Colors.END}",
}
return layers.get(self.layer, "UNKNOWN")
def show_status(self):
print(f"\n{Colors.BOLD}{Colors.CYAN}═══ STATUS: {self.class_name} ═══{Colors.END}")
print(f"Health: {bar(self.health, self.max_health, Colors.RED)}")
print(f"Armor: {bar(self.armor, 100, Colors.YELLOW)}")
print(f"Focus: {bar(self.focus, self.max_focus, Colors.GREEN)}")
print(f"Corruption: {bar(int(self.corruption), 100, Colors.MAGENTA)}")
print(f"Hacking: {self.hacking} Strength: {self.strength} Level: {self.level}")
print(f"Layer: {self._layer_name()}")
print(f"Weapons: {', '.join(w.name for w in self.weapons)}")
if any(self.ammo.values()):
print(f"Ammo: {', '.join([f'{k}={v}' for k, v in self.ammo.items() if v > 0])}")
inv_lines = self.inventory.list_display()
if inv_lines:
print(f"Inventar: {' | '.join(inv_lines)}")
if self.praetor_tokens:
print(f"{Colors.YELLOW}Praetor-Token verfuegbar: {self.praetor_tokens}{Colors.END}")
print(f"{Colors.CYAN}══════════════════════════════{Colors.END}\n")
def to_dict(self):
return {
"player_class": self.player_class,
"health": self.health,
"max_health": self.max_health,
"armor": self.armor,
"focus": self.focus,
"max_focus": self.max_focus,
"hacking": self.hacking,
"strength": self.strength,
"corruption": self.corruption,
"level": self.level,
"praetor_tokens": self.praetor_tokens,
"weapon_ids": [w.weapon_id for w in self.weapons],
"ammo": self.ammo,
"layer": self.layer,
"location": self.location,
"glory_kills": self.glory_kills,
"hacks": self.hacks,
"trace_marks": self.trace_marks,
"flags": self.flags,
"keycards": list(self.inventory.keycards),
"crucible_fragments": self.inventory.crucible_fragments,
"has_backup_pill": self.inventory.has_backup_pill,
}
@classmethod
def from_dict(cls, d):
p = cls(d.get("player_class", "slayer"))
p.health = d["health"]
p.max_health = d["max_health"]
p.armor = d["armor"]
p.focus = d["focus"]
p.max_focus = d["max_focus"]
p.hacking = d["hacking"]
p.strength = d["strength"]
p.corruption = d["corruption"]
p.level = d["level"]
p.praetor_tokens = d["praetor_tokens"]
p.weapons = [make_weapon(wid) for wid in d["weapon_ids"]]
p.ammo = d["ammo"]
p.layer = d["layer"]
p.location = d["location"]
p.glory_kills = d["glory_kills"]
p.hacks = d["hacks"]
p.trace_marks = d["trace_marks"]
p.flags = d["flags"]
p.inventory.keycards = set(d.get("keycards", []))
p.inventory.crucible_fragments = d.get("crucible_fragments", 0)
p.inventory.has_backup_pill = d.get("has_backup_pill", False)
return p