Deterministisches physisches Drop-System
Status: aktiver Game3D-Runtime-Pfad seit Drop-Schema v1.
Verbindlicher Ablauf
Seed + Ruleset
-> immutable RunDefinition.DropPolicy
-> versionierter RunDropSchedule mit ScheduleHash
-> Enemy/Boss stirbt oder Chest wird einmal geoeffnet
-> WorldDrop3D erscheint an der gesicherten Quellposition
-> Spieler laesst ihn liegen oder sammelt ihn ueber CollectDropCommand
-> LocalSoloAuthority validiert und wendet den zentralen Effekt an
-> HUD, Replay und DropRuntimeState werden aktualisiert
Das fruehere Encounter-Choice-Overlay ist fuer neue Runs deaktiviert. Encounter Completion oeffnet Tueren und aktualisiert Objectives unabhaengig davon, ob ein Drop existiert oder eingesammelt wird. Die alten Choice-Contracts bleiben ausschliesslich als Legacy-/Replay-Kompatibilitaet im Code.
Domain, IDs und Versionierung
Die Godot-freie Domain liegt in den einzelnen Typdateien unter HolodeckArena.Shared/Gameplay/Drops. DropKind unterstützt PowerUp, AmmoRestore und HealthRestore; DropSourceType unterstützt Enemy, EliteEnemy, Boss und Chest.
RunDropEntry bindet stabile Drop-ID, SourceEntityId, SourceType, Art, Definition-ID, konkrete PowerUpId, Restore-Modus/-Wert, Sequenz und DefinitionHash. RunDropSchedule enthaelt ordinal sortierte Entries, Catalog-/Balanceversion und SHA-256-ScheduleHash. Die Schedule ist Teil von RunDefinition.DropPolicy und damit Bestandteil des kanonischen RunDefinition-JSON/Hash. Godot-InstanceIds, Nodes und Resources werden nicht gespeichert.
EnemyInstanceIds kommen aus der Objective-/Spawn-Definition. Chest-IDs verwenden chest:{RoomInstanceId}:chest_01. Gleicher Seed, gleiche RunDefinition und gleiche Versionen erzeugen identische Drops; beim Tod oder Oeffnen wird kein Zufall verwendet.
Regeln und vorlaeufiges Balancing
Die zentralen Development-Werte stehen in RunDropScheduleFactory und sind mit drops-balance-2026-07-dev2 versioniert:
- Normale Gegner: 90 % kein Drop, 5 % Ammo, 3 % Health, 2 % Power-up; standardmaessig maximal ein Entry.
- Elite/Miniboss: 40 % kein Drop, 15 % Ammo, 20 % Health, 25 % Power-up.
- Jeder Boss: garantiert genau ein geplantes Power-up; zusaetzlich optional Ammo (~15 %) oder Health (~25 %). Keine post-clear Reward-Chest.
- Jede Treasure-Chest: garantiert ein Power-up; zusaetzlich 15 % Ammo oder 25 % Health.
Mehrere Entries pro Quelle werden durch Sequence unterstuetzt. Das garantierte Boss-/Chest-Power-up wird durch Recovery nie ersetzt. Unbekannte SourceEntityIds loesen nichts aus.
Definitionen und neue Drop-Typen
PhaseOneDropCatalog loest immutable DropDefinition-Daten auf: Visual-, Icon-, Audio- und VFX-ID, Pickup-Radius, Persistenz, Restore-Daten sowie Catalog-/Balanceversion. Finale Assets sind Hooks; fehlende Assets blockieren Gameplay nicht.
Fuer einen neuen Drop-Typ:
- Enum/Definition und zentralen Resolver erweitern.
- ScheduleFactory-Regel in einem eigenen deterministischen Seed-Stream ergaenzen.
- Canonical-/DefinitionHash und Version erhoehen.
- Collector-Effekt ueber bestehende Health-, Ammo-, Power-up- oder Gameplay-Effect-Systeme anbinden.
- Replayvalidator und Tests ergaenzen; keine direkte Attributmutation im Pickup.
WorldDrop, Visuals, Spawnposition und Persistenz
WorldDrop3D ist eine wiederverwendbare Area3D mit CollisionShape, Label und zur Laufzeit erzeugtem Visual. Collision, Pickup und Drop-Daten bleiben im Drop-Node; Visual-Szenen enthalten nur Darstellung (Mesh, Animation, Partikel, Licht).
Visual-Aufloesung:
- Recovery: exportierte
PackedScene-Slots inDropVisualCatalog(AmmoRestoreVisual,HealthRestoreVisual,ArmorRestoreVisual). - Power-ups:
PowerUpDefinition.WorldVisualScene(Game3D-Presentation-Resource), Lookup ueberDropVisualCatalog.PowerUpDefinitionsanhand der stabilen Shared-ID. - Fehlende oder ungueltige Szenen (Root kein
Node3D) fallen auf das Development-Mesh zurueck und erzeugen Warnung/Error.
Katalog: res://Resources/Drops/DropVisualCatalog.tres, referenziert von WorldDrop3D.tscn. Kein per-Spawn-GD.Load ueber String-Pfade.
Neues Recovery-Visual: Szene mit Node3D-Root anlegen und im Catalog-Slot zuweisen.
Neues Power-up-Visual: Szene anlegen, auf der Presentation-PowerUpDefinition als WorldVisualScene setzen und die Definition dem Catalog-Array hinzufuegen. Kein Switch noetig.
Enemy-/Boss-Drops verwenden die vor QueueFree gesicherte autoritative Todesposition. Chest-Drops erscheinen versetzt vor/ueber der Chest. Die aktuelle Dungeon-Szene entlaedt einzelne Raeume nicht; WorldDrops liegt deshalb am Run-World-Root und ueberlebt Raumwechsel. RunDropRuntimeState haelt NotSpawned, Spawned, Collected; diese Zustaende sind die Schnittstelle fuer spaeteres echtes Room-Unloading/Rehydration. Drops leben bis Collection, Completion oder Abort.
Authority und Pickup-Validierung
BodyEntered fordert nur CollectDropCommand(DropId, SourceEntityId) an. LocalRunAuthority validiert Player, Sequenz und Einmaligkeit; das Player-Command-Target und der zentrale Collector pruefen aktiven Run, bekannte und gespawnte Drop-ID, passende Quelle/Definition, lebenden Player, Pickup-Distanz, Effektzulaessigkeit und nicht bereits erfolgte Collection.
Bei Ablehnung bleibt der Drop liegen. Es gibt keine spontane Neuauslosung oder Umwandlung. Der WorldDrop greift nie direkt auf Health, Ammo oder Power-up-Stacks zu.
Effekte
Ammo Restore laeuft ueber AdvancedWeaponController.RestoreEquippedAmmo und WeaponAmmoRuntime.RestoreFull. Nur Primary und Secondary werden verarbeitet. Effektive, bereits durch Modifier veraenderte Magazine-/Reserve-Maxima werden verwendet. Laufende Reloads werden abgebrochen; beide Magazine und Reserven werden atomar gefuellt und das HUD einmal publiziert. Sind beide Slots voll, bleibt der Drop nach Standardpolicy liegen.
Health Restore unterstuetzt FixedAmount, PercentageOfMaximum und FullRestore. HealthRestoreResolver klemmt auf MaxHealth; die Anwendung laeuft ueber HealthComponent.Heal und loest ein HUD-Update aus. Bei voller Gesundheit bleibt der Drop nach Standardpolicy liegen.
Power-up-Drops tragen genau eine PowerUpId. RunPowerUpState.ApplyDrop prueft Catalog, Inkompatibilitaeten und MaximumStacks, wendet die bestehende Modifier-/Triggered-Effect-Pipeline an und aktualisiert das aktive Power-up-HUD. Bei Max-Stack bleibt der Drop liegen. Es wird kein ChoiceSet erzeugt und kein Auswahl-Overlay geoeffnet.
HUD, Audio/VFX und Diagnose
Der Drop zeigt ein World-Label. Nach Collection meldet das Run-HUD "Munition vollstaendig aufgefuellt", den tatsaechlichen Health-Zuwachs oder Power-up-Name/Stack. Recovery-Drops erscheinen nicht in der aktiven Power-up-Liste. Definitionen enthalten austauschbare Audio-/VFX-Hooks; Phase 1 verwendet Development-Emission statt finaler Assets.
Developer-Logs verwenden event=DropFlow.Resolved, DropFlow.Spawned und DropFlow.Collected; es gibt keine Frame-Logs. DevelopmentTriggerPowerUpChoice meldet nur noch, dass Choices deaktiviert sind.
Replay und spaetere Servervalidierung
Der lokale Recorder schreibt drop_scheduled, drop_spawned, drop_collected, drop_collection_rejected (einmal pro Drop/Reason), ammo_restored, health_restored und powerup_applied. Drops werden nicht magnetisiert; Einsammeln nur bei Kontakt (BodyEntered). Abgelehnte Pickups (z. B. volle Ammo) werden nicht pro Frame erneut geloggt. IDs, Quelle/Art, PowerUpId, Simulationstick beziehungsweise Eventtick, Position sowie Vorher-/Nachher-Zustaende werden als reine Werte erfasst.
Der regelbasierte Nakama-Validator behandelt ammo_restored als Vollauffuellung beider gelockten Waffen und setzt deren Magazin-Schusszaehler zurueck. Eine spaetere vollstaendige Re-Simulation kann zusaetzlich ScheduleHash/DefinitionHash neu berechnen, Source-Completion gegen Enemy-/Boss-/Chest-Events pruefen, Spawn/Collection deduplizieren, Distanz plausibilisieren und Effekte gegen RunDefinition verifizieren.
Cleanup und Chest-Integration
Completion und Abort deaktivieren Combat, leeren runlokale Power-ups, entfernen Enemy-Nodes und alle WorldDrops und verwerfen RunDropRuntimeState. Ein Folgerun baut Schedule, IDs und State neu auf. Ammo/Health werden nicht in den Hub uebertragen.
DungeonChest3D ist der Development-Vertical-Slice: stabile Chest-ID, idempotentes oeffnen und Drop-Aufloesung. Mehrfachinteraktion erzeugt keine zusaetzlichen Entries.
Tests und manuelle Pruefung
DropSystemTests deckt Determinismus/Hash, Verteilung, garantierte Boss-/Chest-Power-ups, unbekannte Quellen, Spawn-/Collect-Deduplizierung, beide Ammo-Slots, Reload, Full-Policies, alle Health-Modi und exakte PowerUpId/Max-Stack ab. Encounter-Tests sichern weiterhin, dass Completion nicht auf Pickups wartet.
Manuell im DEV-Run:
- ScheduleHash und
drop_schedulednotieren; Run mit gleichem Seed wiederholen. - Gegner ohne und mit geplanten Ammo-/Health-/Power-up-Entries toeten.
- Ammo beider Slots teilweise leeren, Ammo-Drop sammeln, danach bei vollen Slots erneut beruehren.
- Schaden nehmen, Health-Drop sammeln, danach bei Full Health beruehren.
- Power-up sammeln und pruefen, dass kein Overlay/Cursor-/Combat-Pause-Wechsel erfolgt.
- Boss toeten, garantierten Drop liegen lassen, Raum wechseln/zurueckkehren und erst danach sammeln.
- Treasure-Chest mehrfach benutzen; Drops duerfen nur einmal entstehen.
- Exit erst betreten, nachdem der gewuenschte Boss-Drop gesammelt oder bewusst liegen gelassen wurde.
- Completion/Abort und Folgerun auf alte Drops, IDs, Stacks, Ammo und Health pruefen.