# Kernspiel
Siehe `base.md` für Vision und Ziel. Dieses Dokument beschreibt die Implementierung.

## Run-Loop
- Welt mit Taverne im Zentrum, regelmäßig spawnen Portale (je ein Dungeon)
- Pro Welle zusätzlich **ein rotes Portal** (= deutlich stärkerer Dungeon)
- Portal-Clear (Dungeon-Boss besiegt) → XP → Level-Up **verdoppelt alle Attribute**
- Timer 1h pro Welle. Läuft er ab, ohne rotes Portal besiegt: Monster des roten Portals brechen aus → Invasion greift Taverne an
- Welle endet:
  - Rotes Portal besiegt ODER Invasion abgewehrt → nächste Welle, alles stärker
  - Taverne zerstört → **Game Over** (harter Reset, neuer Run)

# Projektstruktur

## Ordnerstruktur
Drei Grundordner nach Verantwortung. Resources liegen bei ihren Skripten.
```
scenes/                   — Darstellung + Input
  effect_icon_factory.gd  — Shared Utility (statisch, Effekt-Icon-Erstellung)
  healthbar.gd            — Health-Anzeige + Viewport-Setup
  healthbar_shield.gd     — Shield-Anzeige
  healthbar_status.gd     — Target-Border + Aggro-Farbwechsel
  healthbar_effects.gd    — Effekt-Icons auf Healthbar
  player/                 — Spieler + player_stats
  role/                 — Rollenwechsel + Ability/AbilitySet-Klassen
    damage/             — set.tres + abilities/
    tank/               — set.tres + abilities/
    healer/             — set.tres + abilities/
  enemy/                  — Gegner + enemy_stats
  boss/                 — Boss + boss_stats
  portal/                 — Portal + Gate + portal_stats
  dungeon/                — Dungeon + dungeon_manager
  hud/                    — HUD (4 Skripte: vitals, respawn, abilities, effects)
  world/                  — Hauptszene + portal_spawner
systems/                  — Spiellogik
  aggro/                  — AggroSystem (system, tracker, decay, events) + aggro_config
  effect.gd               — Effect Resource (Buff/Debuff/Aura Daten)
  14× *_system.gd         — health, shield, ability, auto_attack, cooldown, enemy_ai, respawn, spawn, effect, element, buff_calc, wave, xp, invasion
  aura_system.gd          — Aura-Propagierung (Child von EffectSystem)
autoloads/                — Globaler Zustand
  event_bus.gd
  game_state.gd
  stats/                  — stats.gd + base_stats.gd
```

## Szenenbaum
- Welt
  - Systems (15 Systeme als Child-Nodes)
  - Taverne
  - Player
  - Portale (dynamisch)
  - Gegner
  - HUD

## Architektur
- Resources (stats/, roles/) — Datenmodelle + Basiswerte, werden später zu Go-Structs + DB
- Autoload (Stats) — Laufzeit-Datenhaltung, wird später zu Server-API-Client
- Systeme — Spiellogik, lesen/schreiben über Stats
- Szenen — Views, rendern + Input, kein Gameplay-State
- EventBus — Signale zwischen Szenen und Systemen
- Flow: Szene → Input → EventBus → System → Stats → EventBus → Szene
- Szenen kennen sich nicht
- Innerhalb einer Szene: direkter Zugriff auf Geschwister erlaubt

# Autoload

## EventBus (autoload/event_bus.gd)
- Intentionen (Input → System):
  - ability_use_requested(player, ability_index)
  - enemy_detected(enemy, player)
- Kampf:
  - attack_executed(attacker, position, direction, damage)
  - damage_dealt(attacker, target, damage)
  - damage_requested(attacker, target, amount)
  - heal_requested(healer, target, amount)
- Entity:
  - entity_died(entity)
  - health_changed(entity, current, max)
  - shield_changed(entity, current, max)
  - shield_broken(entity)
  - shield_regenerated(entity)
- Spieler:
  - target_changed(player, target)
  - player_respawned(player)
  - role_changed(player, role_type)
  - respawn_tick(timer)
  - cooldown_tick(cooldowns, max_cooldowns, gcd_timer)
- Buff:
  - buff_changed(entity, stat, value)
- Gegner:
  - enemy_engaged(enemy, target)
- Portal:
  - portal_spawn(portal, enemies)
  - portal_defeated(portal)
- Dungeon:
  - dungeon_cleared()
- Effects:
  - effect_requested(target, effect, source)
  - effect_applied(target, effect)
  - effect_expired(target, effect)
- Elements:
  - element_damage_dealt(attacker, target, amount, element)
  - element_applied(target, element)
  - element_reaction(target, element_a, element_b, reaction_name)
- Wave:
  - wave_started(wave_number)
  - wave_timer_tick(seconds_remaining)
  - wave_ended(wave_number, success)
- XP / Level:
  - xp_gained(player, amount)
  - level_up(player, new_level)
- Taverne:
  - tavern_damaged(current, max)
  - tavern_destroyed()
- Invasion:
  - invasion_started(enemies)
  - invasion_ended(success)
- Run:
  - run_started(wave_number)
  - game_over()

## Stats (autoload/stats.gd)
- Speichert aktuelle Attribute aller Entities
- Basiswerte aus BaseStats Resource
- player_cache für Szenenwechsel

## GameState (autoload/game_state.gd)
- Speichert Rolle + Position zwischen Szenenwechseln

# Resources

## resources/stats/
### BaseStats (base_stats.gd)
- max_health, health_regen, max_shield, shield_regen_delay, shield_regen_time
### PlayerStats (player_stats.gd, extends BaseStats)
- speed, jump_velocity, target_range, combat_timeout, respawn_time, gcd_time, aa_cooldown
- level, xp, xp_to_next — Level-Up verdoppelt alle Attribute
### EnemyStats (enemy_stats.gd, extends BaseStats)
- speed, attack_range, attack_cooldown, attack_damage, regen_fast, regen_slow, aggro_decay, portal_radius, alert_radius
### BossStats (boss_stats.gd, extends EnemyStats)
### PortalStats (portal_stats.gd, extends BaseStats)
- spawn_count, thresholds
- variant: NORMAL | RED (rotes Portal: höhere HP, stärkere Gegner + Boss)
### TavernStats (tavern_stats.gd, extends BaseStats)
- Nur max_health (kein Schild, kein Regen) — bei 0 HP → tavern_destroyed → Game Over

## resources/roles/
### Ability (ability.gd)
- ability_name, type, damage, ability_range, cooldown, uses_gcd, aoe_radius, icon, is_heal, passive_stat, element
- Typen: Single, AOE, Utility, Ult, Passive
### AbilitySet (ability_set.gd)
- abilities (Array[Ability]), aa_damage, aa_range, aa_is_heal
### AbilityModifier (geplant, Zukunft)
- Verändert Ability (Beruf, Prestige)
### Rollen-Ordner (damage/, tank/, healer/)
- set.tres — AbilitySet der Rolle
- abilities/ — 5 Ability .tres pro Rolle (single, aoe, utility, ult, passive)

# Systeme (systems/)
- In jeder Root-Szene instanziert (world.tscn, dungeon.tscn)
- Entities registrieren/deregistrieren sich bei Stats
- Systeme lesen/schreiben über Stats

### HealthSystem (health_system.gd)
- Leben und Lebensregeneration berechnen, Tod bei 0 HP
- Listener: damage_requested, heal_requested
- Event: health_changed, entity_died
### ShieldSystem (shield_system.gd)
- Schild und Schildregeneration berechnen
- absorb(entity, amount) → remaining damage
- Event: shield_changed, shield_broken, shield_regenerated
### RespawnSystem (respawn_system.gd)
- Respawn bei Taverne mit vollen Leben und Schild
- Listener: entity_died
- Event: respawn_tick, player_respawned
### AbilitySystem (ability_system.gd)
- Ability-Ausführung (Single, AOE, Utility, Ult)
- Listener: ability_use_requested
- Event: attack_executed, damage_requested, heal_requested
### AutoAttackSystem (auto_attack_system.gd)
- Auto-Attack-Logik, läuft jeden Frame in _process
- Liest CombatState.in_combat + Targeting.current_target
- Event: damage_requested, heal_requested
### EffectSystem (effect_system.gd)
- Verwaltet Buffs, Debuffs und Auras auf Entities
- Effect Resource (effect.gd): effect_name, type (BUFF/DEBUFF/AURA), stat, value, duration, is_multiplier, aura_radius, tick_interval, element
- State: active_effects Dictionary[Node, Array[Dict]] (effect, source, remaining, tick_timer)
- Kein Stacking: gleicher effect_name auf Entity → wird refreshed statt gestackt
- Passive-Abilities werden als AURA-Effekte erstellt (role_changed → permanente Auras)
- _process: Dauer ticken, abgelaufene entfernen, DoT/HoT-Ticks
- Listener: role_changed, entity_died, effect_requested
- Event: effect_applied, effect_expired
- Children:
  - AuraSystem (aura_system.gd) — Aura-Propagierung im Radius, Buff-Refresh
  - BuffCalcSystem (buff_calc_system.gd) — Multiplier aggregieren → Stats + Shield updaten
  - Event: buff_changed, shield_changed
### ElementSystem (element_system.gd)
- Verwaltet Element-Zustände auf Entities und löst Elementareffekte aus
- Element Enum: NONE, FIRE (erweiterbar)
- State: applied_elements Dictionary[Node, int]
- Nur Entities in Gruppen "enemies" oder "portals" erhalten Elemente
- Bei Element-Schaden: Element auf Ziel anwenden, passenden Effekt erstellen
- Feuer: DoT (3 Schaden/Tick, 2s Interval, 6s Dauer)
- Bei zwei verschiedenen Elementen: Reaktion auslösen (Zukunft)
- Listener: element_damage_dealt, entity_died, effect_expired
- Event: element_applied, element_reaction
### CooldownSystem (cooldown_system.gd)
- Cooldown-Tracking, GCD, AA-Timer per Entity
- register/deregister per Entity, direkte Funktionsaufrufe vom AbilitySystem
- Event: cooldown_tick
### AggroSystem (systems/aggro/)
- Systemweite Werte in AggroConfig Resource (resources/stats/aggro_config.tres)
- aggro_system.gd — Parent, Config halten, Children verdrahten
- aggro_tracker.gd — Aggro-Tabellen, Players-in-Range, Zielwahl, Radius-Helper
- aggro_decay.gd — Combat-Timer, Decay-Berechnung, Spread, Alert
- aggro_events.gd — Signal-Handler (damage_dealt, heal_requested, entity_died, enemy_detected, enemy_lost)
- Event: enemy_engaged
### EnemyAISystem (enemy_ai_system.gd)
- ATTACK-State: Range-Check, Timer, Schaden
- Iteriert Enemies in _physics_process
- Event: damage_requested
### SpawnSystem (spawn_system.gd)
- Portal-HP-Schwellen-Spawning
- Listener: health_changed, entity_died
- Event: portal_spawn
### WaveSystem (wave_system.gd)
- Wellen-Management: Timer (1h), Wellen-Counter, Portal-Skalierung pro Welle
- Startet neuen Run, spawnt 1× rotes Portal pro Welle, steuert normale Portal-Spawns
- Rotes Portal besiegt ODER Invasion abgewehrt → nächste Welle, Portal-Stats skalieren
- Timer-Ablauf ohne rotes Portal besiegt → löst InvasionSystem aus
- Bei tavern_destroyed: Game Over, nach Delay neuen Run starten (Reset: Level 1, Portale weg)
- Event: wave_started, wave_timer_tick, wave_ended, run_started, game_over
- Listener: portal_defeated, invasion_ended, tavern_destroyed
### XpSystem (xp_system.gd)
- XP bei Dungeon-Clear (Boss besiegt); rotes Portal gibt mehr XP
- Level-Up: alle PlayerStats-Attribute ×2, aktuelle HP/Schild auf neues Max heben
- Event: xp_gained, level_up
- Listener: entity_died (Boss), dungeon_cleared
### InvasionSystem (invasion_system.gd)
- Wird von WaveSystem ausgelöst, wenn Timer abläuft ohne rotes Portal besiegt
- Spawnt Monster des roten Portals an Karten-Rändern, Ziel = Taverne
- Schaden an Taverne über HealthSystem (TavernStats registriert wie Entity)
- Alle Invasions-Gegner tot → invasion_ended(true)
- Event: invasion_started, invasion_ended
- Listener: wave_ended (timeout), entity_died (Invasions-Gegner)

# Szenen
- Szenen sind Views — rendern, Input senden, Events empfangen
- Kein Gameplay-State in Szenen (liegt in Stats Autoload)
- Entities registrieren sich bei Stats in _ready(), deregistrieren in _exit_tree()
- Stats cached Spieler-Werte automatisch bei Szenenwechsel (player_cache)

## Welt (world/)
- world.tscn — Hauptszene (100x100m)
  - Systems (alle Systeme als Child-Nodes, siehe Systeme-Sektion)
  - NavigationRegion3D
  - Boden (MeshInstance3D, 100x100m PlaneMesh)
  - Kollision (StaticBody3D, WorldBoundaryShape3D)
  - Licht (DirectionalLight3D, 45°, Schatten)
  - Taverne (StaticBody3D, BoxMesh, Mitte der Karte)
  - Gruppe (tavern)
  - HitArea (Area3D) — nimmt Invasions-Schaden entgegen
  - Healthbar (Sprite3D + SubViewport, groß, nur Health — kein Schild)
  - Registriert bei Stats mit TavernStats Resource
  - Spieler (Instanz von player.tscn)
  - HUD (Instanz von hud.tscn)
  - PortalSpawner (Node, portal_spawner.gd)

## Spieler (player/)
- player.tscn — CharacterBody3D
  - Gruppe (player)
  - Kollision (CapsuleShape3D, 1.8m x 0.3m)
  - Mesh (CapsuleMesh)
  - CameraPivot (Node3D, camera.gd)
  - Camera3D
  - Movement (Node, movement.gd) — WASD + Springen, liest Werte von Stats
  - Ability (Node, ability.gd) — Input-Handler 1/2/3/4, emittiert ability_use_requested
  - Role (Node, role/role.gd) — Rollenwechsel ALT+1/2/3, emittiert role_changed (auch bei _ready)
  - Targeting (Node, targeting.gd) — Klick/TAB/Auto-Target, emittiert target_changed
- init.gd — Registriert bei Stats mit PlayerStats Resource, Sichtbarkeit bei Tod/Respawn
- camera.gd — LMB freies Umsehen, RMB Kamera + Laufrichtung
- Combat-State (in_combat, Combat-Timer) wird im AggroSystem (aggro_decay.gd) getrackt, nicht als Player-Node

## Gegner (enemy/)
- enemy.tscn — CharacterBody3D
  - Gruppe (enemies)
  - Kollision (CapsuleShape3D)
  - Mesh (SphereMesh)
  - HitArea (Area3D)
  - DetectionArea (Area3D, Detection-Node, detection.gd, emittiert enemy_detected/lost)
  - NavigationAgent3D
  - Bewegung wird vom AI-System (ai_system.gd) gesteuert — Enemy hat keinen eigenen Movement-Node
  - Healthbar (Sprite3D + SubViewport, healthbar.gd) — Health-Anzeige
  - HealthbarShield (Node, healthbar_shield.gd) — Shield-Anzeige
  - HealthbarStatus (Node, healthbar_status.gd) — Target-Border + Aggro-Farbe
  - HealthbarEffects (Node, healthbar_effects.gd) — Effekt-Icons
- init.gd — Registriert bei Stats mit EnemyStats Resource, Detection-Area Signal
- Aggro-Regeln (Werte in AggroConfig Resource):
  - Aufbau:
  - Schaden = Aggro (1:1), Tank 2x Multiplikator
  - Heilung = 0.5x Aggro auf alle Gegner die Heiler kennen
  - Aggro-Spread: 50% des Aggro an Gegner im alert_radius (10m)
  - Detection-Area (10m): +1 Aggro, Alert an Nachbarn im alert_radius
  - Kampfstatus:
  - Spieler in DetectionArea → immer im Kampf (kein Decay)
  - Spieler verlässt DetectionArea → 5s Combat-Timeout, dann Decay
  - Schaden verursachen setzt Combat-Timer zurück
  - Abbau (nach Combat-Timeout):
  - Basis: -aggro_decay/s (default 1.0)
  - Exponentieller Decay basierend auf Zeit seit Kampfende (1%·2^sekunden)
  - Ohne Aggro: Gegner kehrt zum Portal zurück, regeneriert
  - Bei Spieler-Tod → Aggro auf 0

## Boss (enemy/)
- boss.tscn — wie enemy.tscn aber größer (Mesh lila, 1.5x)
  - Gruppe (enemies, boss)
- Nutzt enemy/init.gd (gleiche Registrierung), aber mit BossStats Resource

## Portal (portal/)
- portal.tscn — StaticBody3D (variant: NORMAL = blau, RED = rot, stärker)
  - Gruppe (portals); rotes Portal zusätzlich in Gruppe (red_portal)
  - Kollision (CylinderShape3D)
  - Mesh (CylinderMesh, blau normal / rot für rotes Portal)
  - HitArea (Area3D)
  - DetectionArea (Area3D, Auto-Targeting bei Betreten)
  - Healthbar (Sprite3D + SubViewport, healthbar.gd)
  - HealthbarShield (Node, healthbar_shield.gd)
  - HealthbarStatus (Node, healthbar_status.gd)
  - HealthbarEffects (Node, healthbar_effects.gd)
- init.gd — Registriert bei Stats mit PortalStats Resource
- Spawnt Gegner bei HP-Schwellen (→ SpawnSystem)

## Gate (portal/)
- gate.tscn — StaticBody3D (keine Kollision)
  - Mesh (CylinderMesh, grün, leuchtend)
  - GateArea (Area3D, 3m Radius)
- gate.gd — Konfigurierbar: target_scene, is_exit
  - Beide Gates bestehen solange Boss lebt, verschwinden bei dungeon_cleared

## Dungeon (dungeon/)
- dungeon.tscn — Geschlossener Raum (15x90m, Wände, dunkles Licht)
  - Systems (alle 12 Systeme, temporär bis Welt parallel läuft)
  - NavigationRegion3D
  - Boden, 4 Wände (StaticBody3D + BoxMesh, 3m hoch)
  - Spieler (Instanz von player.tscn)
  - HUD (Instanz von hud.tscn)
  - Gegnergruppen (4x4 Gegner)
  - Boss (Instanz von boss.tscn)
  - Exit-Gate (Instanz von gate.tscn, is_exit=true)
  - DungeonManager (Node, dungeon_manager.gd)
- Eigene Systems bis Welt parallel läuft (geplant: Reparenting)

## HUD (hud/)
- hud.tscn — CanvasLayer (kein Root-Skript)
  - HealthBar (ProgressBar, Label)
  - ShieldBar (ProgressBar, Label)
  - RespawnTimer (Label, Countdown bei Tod)
  - AbilityBar (HBoxContainer, RoleIcon + Abilities 1-4 + Passive)
  - HudVitals (Node, hud_vitals.gd) — HP/Shield-Bars
  - HudRespawn (Node, hud_respawn.gd) — Respawn-Timer
  - HudAbilities (Node, hud_abilities.gd) — Ability-Bar + Cooldowns + Rollen-Icon
  - HudEffects (Node, hud_effects.gd) — Effekt-Icons (nutzt EffectIconFactory)

# Abilities (Werte)
- Schadens-Klasse:
  - AA: 10 Schaden, 10m
  - 1 Single: 30 Schaden, 20m Range, 2s CD, GCD
  - 2 AOE: 20 Schaden, 5m Range, 3s CD, GCD
  - 3 Utility: Schild sofort auf 100%, 5s CD, kein GCD
  - 4 Ult: 5x Single (50 Schaden) + 2x AOE 3m (20 Schaden), 20m Range, 15s CD, GCD
  - 5 Passive: 50% mehr Schaden Aura, 50m (permanent aktiv, kein CD)
- Tank-Klasse:
  - AA: 5 Schaden, 3m
  - 1 Single: 15 Schaden, 3m Range, 2s CD, GCD
  - 2 AOE: 10 Schaden, 10m Range, 3s CD, GCD
  - 3 Utility: Schild sofort auf 100%, 5s CD, kein GCD
  - 4 Ult: Schild 300%, 20s CD, GCD
  - 5 Passive: 50% mehr Schild Aura, 50m (permanent aktiv, kein CD)
- Heiler-Klasse:
  - AA: 1 Heilung, 20m
  - 1 Single: 15 Heilung, 20m Range, 2s CD, GCD
  - 2 AOE: 10 Heilung, 20m Range, 3s CD, GCD
  - 3 Utility: Schild sofort auf 100%, 5s CD, kein GCD
  - 4 Ult: 25 Heal Single + 10 AOE Heal 3m radius, 20m Range, 15s CD, GCD
  - 5 Passive: 50% mehr Heal Aura, 50m (permanent aktiv, kein CD)
  
---
  
