Fortschritts-Quest v1.0 — Automatisches RPG mit lokalem LLM
This commit is contained in:
@@ -0,0 +1,162 @@
|
||||
"""Character-System: Rassen, Klassen, Stats, Leveling."""
|
||||
|
||||
import random
|
||||
import math
|
||||
|
||||
RACES = [
|
||||
"Kleinwüchsiger Goblin", "Waldelf", "Höhlentroll", "Stadtmensch",
|
||||
"Wüstenork", "Sumpfzwerg", "Eisbarbar", "Schattenkatze",
|
||||
"Steingolem", "Feuerechse", "Nachtalb", "Wolfsjäger",
|
||||
]
|
||||
|
||||
CLASSES = [
|
||||
"Schlachtenbraten", "Kartoffelmagier", "Panzerschmied", "Bratpfannenpaladin",
|
||||
"Würstchenkrieger", "Kaffeepriester", "Bierbrauer-Mönch", "Käsekönigin",
|
||||
"Dosenöffner-Assassin", "Fahrradschurke", "Schneeballhexer", "Teppichkampfkünstler",
|
||||
]
|
||||
|
||||
# Class → stat weights (STR, DEX, INT, VIT, LCK)
|
||||
CLASS_STATS = {
|
||||
"Schlachtenbraten": (8, 3, 1, 7, 2),
|
||||
"Kartoffelmagier": (2, 3, 8, 3, 5),
|
||||
"Panzerschmied": (7, 2, 3, 8, 1),
|
||||
"Bratpfannenpaladin": (6, 4, 4, 6, 3),
|
||||
"Würstchenkrieger": (7, 5, 2, 5, 4),
|
||||
"Kaffeepriester": (3, 4, 7, 3, 6),
|
||||
"Bierbrauer-Mönch": (5, 3, 5, 7, 3),
|
||||
"Käsekönigin": (4, 5, 6, 4, 5),
|
||||
"Dosenöffner-Assassin": (4, 8, 3, 3, 7),
|
||||
"Fahrradschurke": (3, 7, 4, 4, 8),
|
||||
"Schneeballhexer": (2, 4, 8, 3, 5),
|
||||
"Teppichkampfkünstler": (5, 7, 3, 5, 4),
|
||||
}
|
||||
|
||||
# XP curve: xp needed for next level = base * level^1.5
|
||||
def xp_for_level(level: int) -> int:
|
||||
return int(50 * (level ** 1.5))
|
||||
|
||||
class Character:
|
||||
def __init__(self, name: str, race: str, char_class: str):
|
||||
self.name = name
|
||||
self.race = race
|
||||
self.char_class = char_class
|
||||
self.level = 1
|
||||
self.xp = 0
|
||||
self.gold = 10
|
||||
|
||||
stats = CLASS_STATS.get(char_class, (5, 5, 5, 5, 5))
|
||||
self.str = stats[0] + random.randint(0, 2)
|
||||
self.dex = stats[1] + random.randint(0, 2)
|
||||
self.int = stats[2] + random.randint(0, 2)
|
||||
self.vit = stats[3] + random.randint(0, 2)
|
||||
self.lck = stats[4] + random.randint(0, 2)
|
||||
|
||||
self.hp = self.max_hp
|
||||
self.mp = self.max_mp
|
||||
|
||||
self.inventory = []
|
||||
self.equipped = {"weapon": None, "armor": None, "helmet": None, "boots": None, "accessory": None}
|
||||
|
||||
self.kills = 0
|
||||
self.deaths = 0
|
||||
self.quests_done = 0
|
||||
self.steps = 0
|
||||
|
||||
@property
|
||||
def max_hp(self) -> int:
|
||||
return 20 + self.vit * 5 + self.level * 3
|
||||
|
||||
@property
|
||||
def max_mp(self) -> int:
|
||||
return 10 + self.int * 3 + self.level * 2
|
||||
|
||||
@property
|
||||
def attack(self) -> int:
|
||||
weapon_bonus = self.equipped["weapon"].power if self.equipped["weapon"] else 0
|
||||
return self.str * 2 + self.level + weapon_bonus
|
||||
|
||||
@property
|
||||
def defense(self) -> int:
|
||||
armor_bonus = sum(e.power for e in self.equipped.values() if e)
|
||||
return self.vit + armor_bonus
|
||||
|
||||
@property
|
||||
def xp_to_next(self) -> int:
|
||||
return xp_for_level(self.level)
|
||||
|
||||
def gain_xp(self, amount: int) -> bool:
|
||||
"""Gibt XP. Return True bei Level-Up."""
|
||||
self.xp += amount
|
||||
if self.xp >= self.xp_to_next:
|
||||
self.xp -= self.xp_to_next
|
||||
self.level += 1
|
||||
self.hp = self.max_hp
|
||||
self.mp = self.max_mp
|
||||
# Stat growth
|
||||
self.str += random.randint(0, 1)
|
||||
self.dex += random.randint(0, 1)
|
||||
self.int += random.randint(0, 1)
|
||||
self.vit += random.randint(0, 1)
|
||||
self.lck += random.randint(0, 1)
|
||||
return True
|
||||
return False
|
||||
|
||||
def take_damage(self, dmg: int):
|
||||
actual = max(1, dmg - self.defense)
|
||||
self.hp -= actual
|
||||
return actual
|
||||
|
||||
def heal(self):
|
||||
self.hp = self.max_hp
|
||||
self.mp = self.max_mp
|
||||
|
||||
def is_alive(self) -> bool:
|
||||
return self.hp > 0
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {
|
||||
"name": self.name, "race": self.race, "char_class": self.char_class,
|
||||
"level": self.level, "xp": self.xp, "gold": self.gold,
|
||||
"str": self.str, "dex": self.dex, "int": self.int, "vit": self.vit, "lck": self.lck,
|
||||
"hp": self.hp, "mp": self.mp,
|
||||
"kills": self.kills, "deaths": self.deaths, "quests_done": self.quests_done, "steps": self.steps,
|
||||
"inventory": [i.to_dict() for i in self.inventory],
|
||||
"equipped": {k: v.to_dict() if v else None for k, v in self.equipped.items()},
|
||||
}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d: dict) -> "Character":
|
||||
c = cls(d["name"], d["race"], d["char_class"])
|
||||
c.level = d["level"]; c.xp = d["xp"]; c.gold = d["gold"]
|
||||
c.str = d["str"]; c.dex = d["dex"]; c.int = d["int"]; c.vit = d["vit"]; c.lck = d["lck"]
|
||||
c.hp = d["hp"]; c.mp = d["mp"]
|
||||
c.kills = d["kills"]; c.deaths = d["deaths"]; c.quests_done = d["quests_done"]; c.steps = d["steps"]
|
||||
c.inventory = [Item.from_dict(i) for i in d.get("inventory", [])]
|
||||
c.equipped = {
|
||||
k: Item.from_dict(v) if v else None
|
||||
for k, v in d.get("equipped", {}).items()
|
||||
}
|
||||
return c
|
||||
|
||||
|
||||
class Item:
|
||||
def __init__(self, name: str, item_type: str, power: int, value: int, rarity: str = "gewöhnlich"):
|
||||
self.name = name
|
||||
self.item_type = item_type # weapon, armor, helmet, boots, accessory, junk, potion
|
||||
self.power = power
|
||||
self.value = value
|
||||
self.rarity = rarity
|
||||
|
||||
def to_dict(self) -> dict:
|
||||
return {"name": self.name, "item_type": self.item_type, "power": self.power, "value": self.value, "rarity": self.rarity}
|
||||
|
||||
@classmethod
|
||||
def from_dict(cls, d: dict) -> "Item":
|
||||
return cls(d["name"], d["item_type"], d["power"], d["value"], d.get("rarity", "gewöhnlich"))
|
||||
|
||||
def __str__(self):
|
||||
r = {"gewöhnlich": "", "selten": "[cyan]", "episch": "[magenta]", "legendär": "[bold yellow]"}
|
||||
color = r.get(self.rarity, "")
|
||||
prefix = f"{color}" if color else ""
|
||||
suffix = "[/]" if color else ""
|
||||
return f"{prefix}{self.name} (Stärke {self.power}, {self.value} Gold){suffix}"
|
||||
Reference in New Issue
Block a user