Zum Inhalt

native/macos/KuroNativeSaver/Core/CombatDirector.swift

// CombatDirector — Swift mirror of src/engine/modes/combat-director.ts. Seeded spawn
// cadence: antagonist (threat>0.35) + ≤2 CORP support units on seeded beats. Actors
// self-manage motion + fire and emit events on the bus. (Distinct from Flight/FilmDirector.)

import Foundation
import Metal
import simd

struct ActorHost {
    let device: MTLDevice
    let add: (Actor) -> Void
    let accentRGB: () -> SIMD3<Float>
    let enemyRGB: () -> SIMD3<Float>
}

final class CombatDirector {
    private let seed: Int32
    private let bus: EventBus
    private let host: ActorHost
    private var rng: LCG
    private var antagonist: Actor?
    private var support: [Actor] = []
    private var nextSupportT = 10.0

    init(seed: Int32, bus: EventBus, host: ActorHost) {
        self.seed = seed; self.bus = bus; self.host = host
        rng = LCG(seed: seed ^ Int32(bitPattern: 0x00c0_ffee))
    }

    // Disabled for now (2026-06-05 feedback): drones read as glitches, tracers illegible.
    // Infrastructure stays; flip on once actors look like real craft.
    private static let enabled = false

    func update(t: Double, threat: Float) {
        guard CombatDirector.enabled else { return }
        if threat > 0.35 && (antagonist == nil || !(antagonist!.alive)) {
            let a = AntagonistDrone(device: host.device, enemyRGB: host.enemyRGB(), seed: seed) { [weak self] in
                self?.bus.emit(FlightEvent(kind: .incomingFire, intensity: Double(threat)))
            }
            antagonist = a
            host.add(a)
        }
        support = support.filter { $0.alive }
        if threat > 0.4 && support.count < 2 && t > nextSupportT {
            nextSupportT = t + 9 + Double(rng.nextF()) * 13
            if rng.nextF() < 0.6 {
                let crash = rng.nextF() < 0.5
                let s = SupportUnit(device: host.device, accentRGB: host.accentRGB(),
                                    seed: seed &+ Int32(truncatingIfNeeded: Int(t)), crash: crash) { [weak self] in
                    self?.bus.emit(FlightEvent(kind: .unitCrash))
                }
                support.append(s)
                host.add(s)
                bus.emit(FlightEvent(kind: .unitArrive))
            }
        }
    }
}