# Director: Stückkosten Produktion (Balancing) ## Was der Daemon **nicht** macht (häufige Missverständnisse) - **Nicht** `6 × Kategorie` (also kein reiner Multiplikator nur aus der Klassennummer). - **Nicht** `2 × Kategorie` — im **ypdaemon**-Stand gibt es diese Formel **nicht**. - **Nicht** „höheres Zertifikat ⇒ höhere Stückkosten“: Das Zertifikat **begrenzt** nur die Produktpalette (`ftp.category <= certificate`); es wird **nicht** als `Zertifikat × 6` o. Ä. auf die Kosten drauf multipliziert. Die **kanonische** Berechnung lebt in Rust: `DirectorWorker::piece_production_cost` in `src/worker/director.rs` (gleiche Logik beim **Produktionsstart** und bei der **Kostenbasis für Steuer/Marge beim Verkauf** über `resolve_production_piece_cost`). ## Modell - **`falukant_user.certificate`** begrenzt nur, **welche** Produkte wählbar sind (`ftp.category <= certificate` in `QUERY_GET_BEST_PRODUCTION`). Es gibt **keine** höheren Stückkosten nur wegen eines höheren Zertifikats. - Die **Stückkosten** hängen von der **Produktklasse** (`falukant_type.product.category`) und einer **Basis** ab; optional **Headroom-Rabatt**, wenn das Zertifikat **über** der Klasse des produzierten Guts liegt (Erfahrung/Reserve, nicht „Strafe“ fürs Zertifikat). ## Formel (Rust, `DirectorWorker`) ``` raw = PRODUCTION_COST_BASE + product_category × PRODUCTION_COST_PER_PRODUCT_CATEGORY headroom = max(0, certificate − product_category) discount = min(headroom × PRODUCTION_HEADROOM_DISCOUNT_PER_STEP, PRODUCTION_HEADROOM_DISCOUNT_CAP) effektiv_stückkosten = raw × (1 − discount) ``` **Ausgeschrieben mit den Standardkonstanten:** `raw = 6 + 1 × product_category` (Kategorie mindestens 1), dann Rabatt nur bei Headroom. **Beispiele** (Standardkonstanten, ohne Rundung): | Kategorie | Zertifikat | raw | Headroom | effektiv (ca.) | |-----------|------------|-----|----------|----------------| | 1 | 4 | 7 | 3 | 7 × (1 − min(0,105; 0,14)) ≈ **6,27** | | 4 | 4 | 10 | 0 | **10** | **Chargenkosten** beim Start einer Linie: `effektiv_stückkosten × Stückzahl` (Stückzahl bis 100 pro Linie, siehe `create_single_production`). | Konstante | Standard | Bedeutung | |-----------|----------|-----------| | `PRODUCTION_COST_BASE` | `6.0` | fixer Basisanteil pro Stück | | `PRODUCTION_COST_PER_PRODUCT_CATEGORY` | `1.0` | Aufschlag pro Produktklasse (additiv zu 6, **nicht** „6×Kategorie“) | | `PRODUCTION_HEADROOM_DISCOUNT_PER_STEP` | `0.035` | Rabatt pro Headroom-Stufe | | `PRODUCTION_HEADROOM_DISCOUNT_CAP` | `0.14` | maximaler Gesamtrabatt | ## Ranking in SQL (`QUERY_GET_BEST_PRODUCTION`) Sortierung nach **Gewinn pro Minute**, mit **demselben Verkaufs-Modell** wie `DirectorWorker::compute_piece_price_for_percent` / `compute_piece_sell_price` in `director.rs`: 1. **Regionaler Basispreis:** `sell_cost × (worth_percent / 100)` — mit Fahrzeug `MAX(worth_percent)` über alle Filialregionen des Users, sonst nur Region der Direktor-Filiale. 2. **Wissensband:** effektiver Verkaufspreis = Basis × **`0.6 + 0.4 × (k/100)`** mit k = Wissen 0…100 (linear zwischen 60 % und 100 % der Basis). Entspricht `min_price + (max_price − min_price) × k/100` mit `min = 0.6 × Basis`, `max = Basis`. 3. **k:** `(2 × knowledge Spielercharakter + knowledge Direktor) / 3` aus `falukant_data.knowledge` (Produktzeilen für Charakter bzw. Direktor). 4. **Stückkosten:** wie `piece_production_cost` (siehe oben). 5. **Formel:** `(Verkaufspreis/Stück − Stückkosten) / production_time`. **Steuer** im Ranking nicht abgezogen. **UI / Node:** Sollte dieselbe Preislogik wie der Daemon nutzen. Weicht `calcRegionalSellPriceSync` ab (z. B. 70 % statt 60 % unterhalb der Basis), Frontend an **diese** Rust-Formel anpassen — nicht umgekehrt den Daemon „blind“ an eine abweichende UI koppeln. ## Parallelproduktionen `MAX_PARALLEL_PRODUCTIONS` (aktuell 2) bestimmt, wie viele Linien pro Tick Geld binden — unabhängig von der Stückkostenformel.