"""Game-Engine: Auto-Progress, Kämpfe, Loot, Quests, Shop.""" import random import time from character import Character, Item, RACES, CLASSES from llm import NameCache class Monster: def __init__(self, name: str, level: int, hp: int, attack: int, defense: int, xp: int, gold: int): self.name = name self.level = level self.hp = hp self.attack = attack self.defense = defense self.xp = xp self.gold = gold def is_alive(self): return self.hp > 0 class GameEngine: def __init__(self, character: Character): self.character = character self.cache = NameCache() self.cache.refill_async() self.current_location = self.cache.get_location() self.current_quest = self.cache.get_quest(character.level) self.quest_progress = 0 self.quest_target = random.randint(3, 8) self.log = [] self.max_log = 30 def _add_log(self, msg: str): self.log.insert(0, msg) if len(self.log) > self.max_log: self.log = self.log[:self.max_log] def _spawn_monster(self) -> Monster: name = self.cache.get_monster(self.character.level, self.current_location) level = max(1, self.character.level + random.randint(-1, 1)) hp = 10 + level * 5 + random.randint(0, 10) attack = level * 2 + random.randint(0, 3) defense = level + random.randint(0, 2) xp = 5 + level * 3 + random.randint(0, 5) gold = 1 + level + random.randint(0, 3) return Monster(name, level, hp, attack, defense, xp, gold) def _generate_loot(self, monster: Monster) -> Item: item_types = ["weapon", "armor", "helmet", "boots", "accessory", "junk"] item_type = random.choices(item_types, weights=[15, 15, 10, 10, 8, 42])[0] # Rarity based on luck and level roll = random.randint(1, 100) + self.character.lck if roll > 95: rarity = "legendär" elif roll > 80: rarity = "episch" elif roll > 60: rarity = "selten" else: rarity = "gewöhnlich" name = self.cache.get_item(item_type, self.character.level, rarity) rarity_mult = {"gewöhnlich": 1, "selten": 1.5, "episch": 2.5, "legendär": 4} mult = rarity_mult.get(rarity, 1) base_power = self.character.level + random.randint(0, 3) power = max(1, int(base_power * mult)) value = max(1, int((monster.gold + 2) * mult * random.uniform(0.8, 1.2))) return Item(name, item_type, power, value, rarity) def _combat(self, monster: Monster) -> dict: """Führt einen automatischen Kampf durch. Gibt Ergebnis-Dict zurück.""" rounds = 0 while monster.is_alive() and self.character.is_alive(): rounds += 1 # Character attacks char_dmg = max(1, self.character.attack - monster.defense + random.randint(-2, 2)) char_dmg = min(char_dmg, monster.hp) monster.hp -= char_dmg if not monster.is_alive(): break # Monster attacks mon_dmg = max(1, monster.attack - self.character.defense + random.randint(-2, 2)) actual = self.character.take_damage(mon_dmg) if not self.character.is_alive(): return {"result": "death", "rounds": rounds, "monster": monster.name} return {"result": "victory", "rounds": rounds, "monster": monster.name} def _complete_quest(self): self.character.quests_done += 1 quest_gold = 5 + self.character.level * 3 + random.randint(0, 10) quest_xp = 10 + self.character.level * 5 + random.randint(0, 10) self.character.gold += quest_gold leveled = self.character.gain_xp(quest_xp) self._add_log(f"[bold green]✅ Quest abgeschlossen: {self.current_quest}[/]") self._add_log(f"[dim]Belohnung: +{quest_gold} Gold, +{quest_xp} XP[/]") if leveled: self._add_log(f"[bold yellow]⬆️ Stufe {self.character.level} erreicht![/]") self.character.heal() # Travel to new location before new quest self._add_log(f"[blue]🌍 Du machst dich auf den Weg...[/]") self.current_location = self.cache.get_location() self._add_log(f"[blue]🌍 Ankunft in: {self.current_location}[/]") # New quest self.current_quest = self.cache.get_quest(self.character.level) self.quest_progress = 0 self.quest_target = random.randint(3, 8) self._add_log(f"[cyan]📜 Neue Quest: {self.current_quest}[/]") self._add_log(f"[dim]Ziel: Besiege {self.quest_target} Gegner[/]") def step(self) -> dict: """Ein Schritt des Auto-Progress. Gibt Event-Info zurück.""" self.character.steps += 1 events = [] # Random: sometimes travel if random.randint(1, 50) == 1: self.current_location = self.cache.get_location() events.append(("travel", f"[blue]🌍 Du reist nach: {self.current_location}[/]")) self._add_log(events[-1][1]) # Spawn monster monster = self._spawn_monster() events.append(("encounter", f"[red]⚔️ {monster.name} (Stufe {monster.level}) erscheint![/]")) self._add_log(events[-1][1]) # Fight result = self._combat(monster) if result["result"] == "victory": self.character.kills += 1 events.append(("victory", f"[green]⚔️ Besiegst {monster.name} ({result['rounds']} Runden)[/]")) self._add_log(events[-1][1]) # XP + Gold self.character.gold += monster.gold leveled = self.character.gain_xp(monster.xp) events.append(("loot_xp", f"[dim]+{monster.xp} XP, +{monster.gold} Gold[/]")) self._add_log(events[-1][1]) if leveled: self._add_log(f"[bold yellow]⬆️ Stufe {self.character.level} erreicht![/]") self.character.heal() events.append(("levelup", f"[bold yellow]⬆️ STUFE {self.character.level}![/]")) # Loot drop if random.randint(1, 100) <= 70: # 70% drop chance item = self._generate_loot(monster) self._add_log(f"[magenta]📦 Loot: {item}[/]") events.append(("loot", f"[magenta]📦 {item}[/]", item)) self._auto_equip(item) else: # Always some gold extra_gold = random.randint(1, 3) self.character.gold += extra_gold # Quest progress self.quest_progress += 1 if self.quest_progress >= self.quest_target: self._complete_quest() events.append(("quest_done", f"[green]✅ Quest erfüllt![/]", True)) # True = pause flag elif result["result"] == "death": self.character.deaths += 1 events.append(("death", f"[bold red]💀 Von {monster.name} besiegt! Respawn...[/]")) self._add_log(events[-1][1]) # Respawn: lose 10% gold, heal lost_gold = max(1, self.character.gold // 10) self.character.gold -= lost_gold self.character.heal() self._add_log(f"[red]Verlierst {lost_gold} Gold beim Sterben.[/]") return {"events": events} def _auto_equip(self, item: Item): """Prüft ob Item besser ist und rüstet es automatisch aus.""" slot = None if item.item_type in ("weapon", "armor", "helmet", "boots", "accessory"): slot = item.item_type if slot: current = self.character.equipped[slot] if current is None or item.power > current.power: if current: self.character.inventory.append(current) self.character.equipped[slot] = item self._add_log(f"[cyan]🎽 Ausgerüstet: {item}[/]") else: self.character.inventory.append(item) else: self.character.inventory.append(item) # Auto-sell junk to keep inventory clean if item.item_type == "junk": self.character.gold += item.value if item in self.character.inventory: self.character.inventory.remove(item) self._add_log(f"[dim]💰 Verkauft: {item.name} (+{item.value} Gold)[/]") def _sell_junk(self): """Verkauft alle Schrott-Items.""" sold = 0 total_gold = 0 for item in self.character.inventory[:]: if item.item_type == "junk": self.character.inventory.remove(item) self.character.gold += item.value total_gold += item.value sold += 1 if sold > 0: self._add_log(f"[dim]💰 {sold} Schrott verkauft (+{total_gold} Gold)[/]") def get_state(self) -> dict: return { "character": self.character.to_dict(), "current_location": self.current_location, "current_quest": self.current_quest, "quest_progress": self.quest_progress, "quest_target": self.quest_target, "log": self.log, } def save(self, path: str): import json with open(path, "w") as f: json.dump(self.get_state(), f, ensure_ascii=False, indent=2) @classmethod def load(cls, path: str) -> "GameEngine": import json with open(path) as f: d = json.load(f) char = Character.from_dict(d["character"]) engine = cls(char) engine.current_location = d.get("current_location", engine.current_location) engine.current_quest = d.get("current_quest", engine.current_quest) engine.quest_progress = d.get("quest_progress", 0) engine.quest_target = d.get("quest_target", 5) engine.log = d.get("log", []) return engine