From 63d0f3e64d79eb0e3ee28e70fc60f496a60788da Mon Sep 17 00:00:00 2001 From: Andre Date: Thu, 19 Mar 2026 21:37:19 +0100 Subject: [PATCH] feat: Zornfesseln implementiert (Krieger Level 28) MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit - Zieht Gegner in Reichweite 12m heran (Pull-Effekt 0.6s) - Nach dem Pull: automatischer Schlag 20-30 + 80% Stärke - enemy.gd: apply_pull() + Pull überschreibt KI-Bewegung - Kostet 35 Wut, Cooldown 14s Co-Authored-By: Claude Sonnet 4.6 --- enemy.gd | 27 +++++++++++++++++++++++++++ player.gd | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+) diff --git a/enemy.gd b/enemy.gd index 8090d6e..c1c04df 100644 --- a/enemy.gd +++ b/enemy.gd @@ -54,6 +54,11 @@ var is_dead: bool = false var _slow_timer: float = 0.0 var _slow_factor: float = 1.0 # 1.0 = normal, 0.5 = 50% langsamer +# Pull (Zornfesseln) +var _pull_target: Node3D = null +var _pull_timer: float = 0.0 +const PULL_SPEED: float = 18.0 + # Patrol @export var patrol_radius: float = 8.0 @export var patrol_speed: float = 1.5 # Laufgeschwindigkeit beim Patrouillieren @@ -229,6 +234,23 @@ func _physics_process(delta): if _slow_timer <= 0.0: _slow_factor = 1.0 + # Pull-Effekt (Zornfesseln) + if _pull_timer > 0.0 and _pull_target != null and is_instance_valid(_pull_target): + _pull_timer -= delta + var dir = (_pull_target.global_position - global_position) + dir.y = 0 + if dir.length() > 1.0: + dir = dir.normalized() + velocity.x = dir.x * PULL_SPEED + velocity.z = dir.z * PULL_SPEED + else: + _pull_timer = 0.0 # Nah genug — Pull beendet + + # Pull aktiv → normale KI überspringen + if _pull_timer > 0.0: + move_and_slide() + return + # Kein Ziel → Spieler suchen if target == null or not is_instance_valid(target): target = null @@ -416,6 +438,11 @@ func _perform_attack(): _play_anim("autoattack") print(name + " greift an: " + str(damage) + " Schaden") +func apply_pull(source: Node3D, duration: float): + _pull_target = source + _pull_timer = duration + state = State.CHASING # Aggro auslösen + func apply_slow(factor: float, duration: float): _slow_factor = clamp(factor, 0.1, 1.0) _slow_timer = duration diff --git a/player.gd b/player.gd index e8bd00e..e90ce16 100644 --- a/player.gd +++ b/player.gd @@ -97,6 +97,10 @@ var is_defending: bool = false var _defend_timer: float = 0.0 var _defend_mode: String = "" # "schildwall" oder "trotz" +# Zornfesseln — verzögerter Schlag nach Pull +var _zornfesseln_target = null +var _zornfesseln_strike_timer: float = 0.0 + # Blutrausch — Blutungs-DOT var _bleed_target = null var _bleed_timer: float = 0.0 # verbleibende Dauer @@ -155,6 +159,10 @@ const BLUTRAUSCH_DOT_DAMAGE: int = 4 # Schaden pro Tick const WIRBELWIND_COOLDOWN: float = 6.0 const WIRBELWIND_RADIUS: float = 3.5 const WIRBELWIND_RAGE: int = 40 +const ZORNFESSELN_COOLDOWN: float = 14.0 +const ZORNFESSELN_RANGE: float = 12.0 # Max Zielreichweite +const ZORNFESSELN_RAGE: int = 35 +const ZORNFESSELN_PULL_DURATION: float = 0.6 # Sekunden bis Gegner da ist # Cast System var is_casting: bool = false @@ -296,6 +304,15 @@ func _init_class_skills(): "cooldown": TEKTONISCHER_SCHLAG_COOLDOWN, "cast_time": 0.0, }) + if level >= 28: + available_skills.append({ + "id": "zornfesseln", + "name": "Zornfesseln", + "description": "Reißt einen Gegner heran und schlägt ihn mit voller Wucht.", + "icon": "res://icons/zornfesseln_icon.svg", + "cooldown": ZORNFESSELN_COOLDOWN, + "cast_time": 0.0, + }) if level >= 20: available_skills.append({ "id": "wirbelwind", @@ -680,6 +697,10 @@ func execute_skill(skill_id: String): if current_resource < WIRBELWIND_RAGE: print("Zu wenig Wut!") return + if skill_id == "zornfesseln": + if current_resource < ZORNFESSELN_RAGE: + print("Zu wenig Wut!") + return # Cast-Zeit? if skill["cast_time"] > 0: @@ -720,6 +741,8 @@ func _apply_skill(skill_id: String): _do_blutrausch() "wirbelwind": _do_wirbelwind() + "zornfesseln": + _do_zornfesseln() # ─── Autoattack ─────────────────────────────────────────────── @@ -812,6 +835,24 @@ func _do_wirbelwind(): trigger_global_cooldown() print("Wirbelwind! %d Gegner getroffen" % hit_count) +# ─── Zornfesseln ────────────────────────────────────────────── + +func _do_zornfesseln(): + if target == null or not is_instance_valid(target): + return + var dist = global_position.distance_to(target.global_position) + if dist > ZORNFESSELN_RANGE: + print("Ziel zu weit für Zornfesseln!") + return + if not _spend_rage(ZORNFESSELN_RAGE): + return + target.apply_pull(self, ZORNFESSELN_PULL_DURATION) + _zornfesseln_target = target + _zornfesseln_strike_timer = ZORNFESSELN_PULL_DURATION + skill_cooldowns["zornfesseln"] = ZORNFESSELN_COOLDOWN + trigger_global_cooldown() + print("Zornfesseln! Gegner wird herangezogen...") + # ─── Durchbeißen / Schildwall / Trotz ──────────────────────── # ─── Blutrausch ─────────────────────────────────────────────── @@ -1168,6 +1209,16 @@ func _physics_process(delta): # ── Wut-Verfall ─────────────────────────────────────────── _update_rage_decay(delta) + # ── Zornfesseln Schlag ──────────────────────────────────── + if _zornfesseln_strike_timer > 0.0: + _zornfesseln_strike_timer -= delta + if _zornfesseln_strike_timer <= 0.0: + if _zornfesseln_target != null and is_instance_valid(_zornfesseln_target): + var damage = randi_range(20, 30) + int(strength * 0.8) + _zornfesseln_target.take_damage(damage) + print("Zornfesseln Schlag! %d Schaden" % damage) + _zornfesseln_target = null + # ── Blutungs-DOT ────────────────────────────────────────── if _bleed_timer > 0.0: _bleed_timer -= delta