Files
mmo/plan.md
Marek Lenczewski cf5979803e wahnsinn
2026-04-16 15:11:15 +02:00

389 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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)
---