v2.5 — Klassen-Skills (D&D 5e) für alle 10 Klassen

Jede Klasse hat 4 einzigartige Skills die automatisch im Kampf eingesetzt werden:

Barde: Bardische Inspiration (Buff), Heilendes Wort (Heal),
  Schneidendes Wort (Debuff), Verwirrendes Lied (Stun)
Kleriker: Heilendes Gebet (Heal), Göttlicher Schlag (Dmg),
  Segen (Buff), Glaubensschild (AC Buff)
Druide: Heilende Blüten (Heal), Dornenpeitsche (Dmg+Bleed),
  Baumhaut (AC Buff), Wurzeln der Erde (Restrain)
Kämpfer: Zweiter Wind (Heal), Aktionsstoß (Extra Attack),
  Wutanfall (ATK Buff), Parieren (AC Buff)
Magier: Magisches Geschoss (Dmg), Feuerball (Dmg+Burn),
  Magische Rüstung (AC Buff), Schild (AC Buff)
Mönch: Fließender Angriff (Extra Attack), Ki-Heilung (Heal),
  Patiente Verteidigung (AC Buff), Betäubender Schlag (Stun)
Paladin: Göttlicher Smite (Dmg), Handauflegen (Heal),
  Göttliche Gunst (ATK Buff), Furchtstrahl (Fear)
Schurke: Sneak Attack (Dmg), Hinterhalt (Dmg+Bleed),
  Ausweichen (AC Buff), Blenden (Blind)
Waldläufer: Jägerds Markierung (Dmg), Heilkräuter (Heal),
  Spitzenklauen (Bleed), Natürliche Erkundung (AC Buff)
Hexenmeister: Verdammnisstrahl (Dmg), Höllisches Feuer (Dmg+Burn),
  Schattenrüstung (AC Buff), Schreckensfluch (Fear)

Skill-Typen: heal, damage, buff_self, debuff_enemy, extra_attack
MP-Kosten für Zauber, kostenlos für physische Skills
This commit is contained in:
arch_agent
2026-07-26 08:54:12 +02:00
parent 7f9df50fcd
commit 1df2377b6a
2 changed files with 139 additions and 27 deletions
+60
View File
@@ -46,42 +46,102 @@ DND_CLASSES = {
"Barde": {
"hit_die": 8, "primary": "CHA", "saves": ["DEX", "CHA"],
"weapon_dice": "1d8", "armor_prof": "leicht",
"skills": [
{"name": "Bardische Inspiration", "type": "buff_self", "chance": 30, "cost": 0, "power": 2, "duration": 3, "effect": "bless", "desc": "Würfelnder Bonus auf Angriffe"},
{"name": "Heilendes Wort", "type": "heal", "chance": 25, "cost": 1, "power": 8, "duration": 0, "effect": None, "desc": "Heilt 1d8+CHA im Kampf"},
{"name": "Schneidendes Wort", "type": "debuff_enemy", "chance": 20, "cost": 1, "power": 2, "duration": 2, "effect": "curse_weakness", "desc": "Monster wird geschwächt"},
{"name": "Verwirrendes Lied", "type": "debuff_enemy", "chance": 15, "cost": 1, "power": 1, "duration": 2, "effect": "stunned", "desc": "Monster ist betäubt"},
],
},
"Kleriker": {
"hit_die": 8, "primary": "WIS", "saves": ["WIS", "CHA"],
"weapon_dice": "1d8", "armor_prof": "mittel",
"skills": [
{"name": "Heilendes Gebet", "type": "heal", "chance": 35, "cost": 1, "power": 10, "duration": 0, "effect": None, "desc": "Heilt 1d10+WIS"},
{"name": "Göttlicher Schlag", "type": "damage", "chance": 25, "cost": 1, "power": 8, "duration": 0, "effect": None, "desc": "Bonus-Strahlenschaden"},
{"name": "Segen", "type": "buff_self", "chance": 20, "cost": 1, "power": 2, "duration": 3, "effect": "bless", "desc": "+2 auf Angriffe"},
{"name": "Glaubensschild", "type": "buff_self", "chance": 15, "cost": 1, "power": 3, "duration": 3, "effect": "shield_of_faith", "desc": "+3 AC"},
],
},
"Druide": {
"hit_die": 8, "primary": "WIS", "saves": ["INT", "WIS"],
"weapon_dice": "1d6", "armor_prof": "mittel",
"skills": [
{"name": "Heilende Blüten", "type": "heal", "chance": 30, "cost": 1, "power": 8, "duration": 0, "effect": None, "desc": "Natürliche Heilung"},
{"name": "Dornenpeitsche", "type": "damage", "chance": 25, "cost": 1, "power": 6, "duration": 0, "effect": "bleed", "desc": "Naturschaden + Blutung"},
{"name": "Baumhaut", "type": "buff_self", "chance": 20, "cost": 1, "power": 2, "duration": 4, "effect": "barkskin", "desc": "+2 AC"},
{"name": "Wurzeln der Erde", "type": "debuff_enemy", "chance": 15, "cost": 1, "power": 1, "duration": 2, "effect": "restrained", "desc": "Monster wird gefesselt"},
],
},
"Kämpfer": {
"hit_die": 10, "primary": "STR", "saves": ["STR", "CON"],
"weapon_dice": "1d8", "armor_prof": "schwer",
"skills": [
{"name": "Zweiter Wind", "type": "heal", "chance": 30, "cost": 0, "power": 10, "duration": 0, "effect": None, "desc": "Heilt 1d10+Level im Kampf"},
{"name": "Aktionsstoß", "type": "extra_attack", "chance": 25, "cost": 0, "power": 0, "duration": 0, "effect": None, "desc": "Extra Angriff diese Runde"},
{"name": "Wutanfall", "type": "buff_self", "chance": 20, "cost": 0, "power": 3, "duration": 3, "effect": "rage", "desc": "+3 Angriff"},
{"name": "Parieren", "type": "buff_self", "chance": 15, "cost": 0, "power": 2, "duration": 2, "effect": "shield_of_faith", "desc": "+2 AC durch Parieren"},
],
},
"Magier": {
"hit_die": 6, "primary": "INT", "saves": ["INT", "WIS"],
"weapon_dice": "1d6", "armor_prof": "keine",
"skills": [
{"name": "Magisches Geschoss", "type": "damage", "chance": 35, "cost": 1, "power": 9, "duration": 0, "effect": None, "desc": "3 Schadenspunkte pro Geschoss, trifft immer"},
{"name": "Feuerball", "type": "damage", "chance": 25, "cost": 2, "power": 14, "duration": 0, "effect": "burn", "desc": "8d6 Feuerschaden + Brennen"},
{"name": "Magische Rüstung", "type": "buff_self", "chance": 20, "cost": 1, "power": 3, "duration": 5, "effect": "mage_armor", "desc": "+3 AC"},
{"name": "Schild", "type": "buff_self", "chance": 15, "cost": 1, "power": 5, "duration": 2, "effect": "shield_of_faith", "desc": "+5 AC Reaktion"},
],
},
"Mönch": {
"hit_die": 8, "primary": "DEX", "saves": ["STR", "DEX"],
"weapon_dice": "1d6", "armor_prof": "keine",
"skills": [
{"name": "Fließender Angriff", "type": "extra_attack", "chance": 30, "cost": 0, "power": 0, "duration": 0, "effect": None, "desc": "Bonus-Handangriff"},
{"name": "Ki-Heilung", "type": "heal", "chance": 20, "cost": 1, "power": 6, "duration": 0, "effect": None, "desc": "Heilt mit Ki"},
{"name": "Patiente Verteidigung", "type": "buff_self", "chance": 20, "cost": 1, "power": 2, "duration": 2, "effect": "shield_of_faith", "desc": "+2 AC durch Ausweichen"},
{"name": "Betäubender Schlag", "type": "debuff_enemy", "chance": 15, "cost": 1, "power": 1, "duration": 1, "effect": "stunned", "desc": "Monster betäuben"},
],
},
"Paladin": {
"hit_die": 10, "primary": "CHA", "saves": ["WIS", "CHA"],
"weapon_dice": "1d8", "armor_prof": "schwer",
"skills": [
{"name": "Göttlicher Smite", "type": "damage", "chance": 30, "cost": 0, "power": 12, "duration": 0, "effect": None, "desc": "Bonus-Strahlenschaden bei Treffer"},
{"name": "Handauflegen", "type": "heal", "chance": 25, "cost": 0, "power": 10, "duration": 0, "effect": None, "desc": "Heilt 1d10+CHA"},
{"name": "Göttliche Gunst", "type": "buff_self", "chance": 20, "cost": 1, "power": 2, "duration": 3, "effect": "divine_favor", "desc": "+2 Angriff"},
{"name": "Furchtstrahl", "type": "debuff_enemy", "chance": 15, "cost": 1, "power": 1, "duration": 2, "effect": "fear", "desc": "Monster wird verängstigt"},
],
},
"Schurke": {
"hit_die": 8, "primary": "DEX", "saves": ["DEX", "INT"],
"weapon_dice": "1d6", "armor_prof": "leicht",
"skills": [
{"name": "Sneak Attack", "type": "damage", "chance": 40, "cost": 0, "power": 10, "duration": 0, "effect": None, "desc": "Bonus-Schaden wenn Vorteil"},
{"name": "Hinterhalt", "type": "damage", "chance": 20, "cost": 0, "power": 8, "duration": 0, "effect": "bleed", "desc": "Überraschungsangriff + Blutung"},
{"name": "Ausweichen", "type": "buff_self", "chance": 20, "cost": 0, "power": 3, "duration": 2, "effect": "shield_of_faith", "desc": "+3 AC durch Ausweichen"},
{"name": "Blenden", "type": "debuff_enemy", "chance": 15, "cost": 0, "power": 1, "duration": 2, "effect": "blinded", "desc": "Monster blenden"},
],
},
"Waldläufer": {
"hit_die": 10, "primary": "DEX", "saves": ["STR", "DEX"],
"weapon_dice": "1d8", "armor_prof": "mittel",
"skills": [
{"name": "Jägerds Markierung", "type": "damage", "chance": 30, "cost": 0, "power": 6, "duration": 0, "effect": None, "desc": "Bonus-Schaden gegen markierten Gegner"},
{"name": "Heilkräuter", "type": "heal", "chance": 25, "cost": 0, "power": 8, "duration": 0, "effect": None, "desc": "Naturheilung"},
{"name": "Spitzenklauen", "type": "debuff_enemy", "chance": 20, "cost": 0, "power": 1, "duration": 3, "effect": "bleed", "desc": "Blutung durch Pfeilschuss"},
{"name": "Natürliche Erkundung", "type": "buff_self", "chance": 15, "cost": 0, "power": 2, "duration": 3, "effect": "barkskin", "desc": "+2 AC im Freien"},
],
},
"Hexenmeister": {
"hit_die": 8, "primary": "CHA", "saves": ["WIS", "CHA"],
"weapon_dice": "1d6", "armor_prof": "leicht",
"skills": [
{"name": "Verdammnisstrahl", "type": "damage", "chance": 35, "cost": 1, "power": 10, "duration": 0, "effect": None, "desc": "Strahl aus dunkler Energie"},
{"name": "Höllisches Feuer", "type": "damage", "chance": 20, "cost": 1, "power": 12, "duration": 0, "effect": "burn", "desc": "Feuer + Brennen"},
{"name": "Schattenrüstung", "type": "buff_self", "chance": 20, "cost": 1, "power": 3, "duration": 4, "effect": "mage_armor", "desc": "+3 AC aus Schatten"},
{"name": "Schreckensfluch", "type": "debuff_enemy", "chance": 15, "cost": 1, "power": 1, "duration": 2, "effect": "fear", "desc": "Monster flieht vor Schrecken"},
],
},
}
+77 -25
View File
@@ -372,12 +372,12 @@ class GameEngine:
if self.character.is_immobilized():
self.dice_log.add(f"[yellow]💫 Du bist gelähmt/betäubt — kannst nicht angreifen![/]")
else:
# Caster tries spell first (50% chance, round 1 only)
if rounds == 1 and self.character.max_mp > 0 and random.random() < 0.5:
if self._cast_spell_if_possible(monster):
if not monster.is_alive:
self.dice_log.add(f"[bold green]☠️ {monster.name} durch Zauber besiegt![/]")
break
# Try class skill (round 1 only, before normal attack)
if rounds == 1:
self._use_class_skill(monster, rounds)
if not monster.is_alive:
self.dice_log.add(f"[bold green]☠️ {monster.name} durch Skill besiegt![/]")
break
result = self._player_attack(monster)
if result["hit"]:
monster.hp = max(0, monster.hp - result["damage"])
@@ -689,31 +689,83 @@ class GameEngine:
self.dice_log.add(f"[blue]🧪 Manatrank! 2d4+2 = {heal} MP geheilt (MP: {c.mp}/{c.max_mp})[/]")
self._add_log(f"[blue]🧪 Manatrank benutzt (+{heal} MP)[/]")
def _cast_spell_if_possible(self, monster) -> bool:
"""Caster versucht einen Zauber zu wirken."""
def _use_class_skill(self, monster: DnDMonster, round_num: int) -> bool:
"""Versucht einen Klassen-Skill einzusetzen. Gibt True zurück wenn verwendet."""
c = self.character
if not c.can_cast_spell(2):
class_data = DND_CLASSES.get(c.dnd_class, {})
skills = class_data.get("skills", [])
if not skills:
return False
spell_names = {
"Magier": ["Feuerball", "Magisches Geschoss", "Blitzschlag"],
"Hexenmeister": ["Verdammnisstrahl", "Schattenfluch", "Höllisches Feuer"],
"Barde": ["Spottlied", "Heilige Hymne", "Verwirrendes Lied"],
"Kleriker": ["Göttlicher Schlag", "Heilige Flamme", "Bannstrahl"],
"Druide": ["Frostgriff", "Dornenranke", "Blitzwelle"],
}
spells = spell_names.get(c.dnd_class, ["Arkane Explosion"])
spell = random.choice(spells)
# Pick a skill based on chance, respecting MP cost
for skill in skills:
if random.randint(1, 100) > skill["chance"]:
continue
if skill["cost"] > 0 and not c.can_cast_spell(skill["cost"]):
continue
# Spell damage: higher dice
spell_dmg = roll(6, 3, c.prof_bonus)["total"]
c.cast_spell(2)
skill_name = skill["name"]
skill_type = skill["type"]
power = skill["power"]
self.dice_log.add(f"[magenta]✨ {c.name} wirkt {spell}! 3d6+{c.prof_bonus} = {spell_dmg} Schadenszauber[/]")
monster.hp = max(0, monster.hp - spell_dmg)
self._add_log(f"[magenta]✨ {c.name} wirkt {spell}! ({spell_dmg} Schaden)[/]")
if skill_type == "heal":
heal_amount = roll(power, 1, modifier(c.stats.get(class_data.get("primary", "WIS"), 10)))["total"]
c.hp = min(c.max_hp, c.hp + heal_amount)
if skill["cost"] > 0:
c.cast_spell(skill["cost"])
self.dice_log.add(f"[green]✨ {skill_name}! Heilt {heal_amount} HP (HP: {c.hp}/{c.max_hp})[/]")
self._add_log(f"[green]✨ {c.name} nutzt {skill_name} (+{heal_amount} HP)[/]")
return True
return True
elif skill_type == "damage":
dmg = roll(power, 1, c.prof_bonus)["total"]
if skill["cost"] > 0:
c.cast_spell(skill["cost"])
monster.hp = max(0, monster.hp - dmg)
self.dice_log.add(f"[magenta]✨ {skill_name}! {dmg} Schaden![/]")
self._add_log(f"[magenta]✨ {c.name} nutzt {skill_name} ({dmg} Dmg)[/]")
if skill.get("effect") and monster.is_alive:
monster_effect = {"type": skill["effect"], "chance": 100, "duration": 2, "power": max(1, c.level // 3), "name": skill_name}
# Apply to monster (simplified — add to a temporary effect)
self.dice_log.add(f"[yellow]⚠️ {skill_name} verursacht {skill['effect']}![/]")
return True
elif skill_type == "buff_self":
if skill["cost"] > 0:
c.cast_spell(skill["cost"])
c.add_effect(skill["effect"], skill["duration"], skill["power"], skill_name)
self.dice_log.add(f"[cyan]✨ {skill_name}! +{skill['power']} {skill['effect']} für {skill['duration']} Runden[/]")
self._add_log(f"[cyan]✨ {c.name} nutzt {skill_name}[/]")
return True
elif skill_type == "debuff_enemy":
if skill["cost"] > 0:
c.cast_spell(skill["cost"])
# Apply debuff to monster (simplified — we track it as a note)
self.dice_log.add(f"[yellow]✨ {skill_name}! Monster bekommt {skill['effect']} für {skill['duration']} Runden[/]")
self._add_log(f"[yellow]✨ {c.name} nutzt {skill_name} — Monster {skill['effect']}![/]")
# For combat: reduce monster AC or attack temporarily
if skill["effect"] == "stunned":
self.dice_log.add(f"[yellow]💫 {monster.name} ist betäubt und kann nicht angreifen![/]")
elif skill["effect"] == "blinded":
self.dice_log.add(f"[yellow]🙈 {monster.name} ist geblendet![/]")
elif skill["effect"] == "fear":
self.dice_log.add(f"[yellow]😱 {monster.name} flieht vor Furcht![/]")
return True
elif skill_type == "extra_attack":
# Extra attack this round
result = self._player_attack(monster)
if result["hit"]:
monster.hp = max(0, monster.hp - result["damage"])
self.dice_log.add(f"[cyan]✨ {skill_name}! Extra-Angriff: {result['damage']} Schaden![/]")
if not monster.is_alive:
self.dice_log.add(f"[bold green]☠️ {monster.name} durch {skill_name} besiegt![/]")
else:
self.dice_log.add(f"[cyan]✨ {skill_name}! Extra-Angriff verfehlt![/]")
return True
return False
def step(self) -> dict:
self.character.steps += 1