All-in-One Namensgenerator v11.0

Keine Kompromisse mehr: Alle Module mit einer finalen, massiven Basis von über 250 Grundbegriffen.

当前为 2025-08-21 提交的版本,查看 最新版本

// ==UserScript==
// @name         All-in-One Namensgenerator v11.0
// @namespace    http://tampermonkey.net/
// @version      11.0
// @description  Keine Kompromisse mehr: Alle Module mit einer finalen, massiven Basis von über 250 Grundbegriffen.
// @author       Gemini & User-Input
// @match        https://www.leitstellenspiel.de/*
// @grant        GM_addStyle
// @grant        GM_xmlhttpRequest
// @connect      self
// ==/UserScript==

(function() {
    'use strict';

    // ========================================================================
    // 1. STYLES
    // ========================================================================
    GM_addStyle(`
        #ng-modal-overlay { position: fixed; top: 0; left: 0; width: 100%; height: 100%; background-color: rgba(0, 0, 0, 0.7); z-index: 9999; display: flex; justify-content: center; align-items: center; }
        #ng-modal-content { background-color: #282c34; color: #fff; padding: 20px; border-radius: 8px; width: 700px; max-width: 90%; max-height: 90vh; border: 1px solid #444; display: flex; flex-direction: column; }
        #ng-modal-content h3 { margin-top: 0; border-bottom: 1px solid #555; padding-bottom: 10px; }
        #ng-modal-body { flex-grow: 1; overflow-y: auto; margin-bottom: 15px; padding-right: 10px; }
        #ng-log-area { width: 100%; height: 200px; background-color: #1e1e1e; color: #d4d4d4; font-family: monospace; font-size: 12px; border: 1px solid #555; border-radius: 4px; padding: 5px; overflow-y: scroll; resize: vertical; margin-top: 10px; }
        #ng-progress-bar-container { width: 100%; background-color: #555; border-radius: 5px; }
        #ng-progress-bar { width: 0%; height: 20px; background-color: #007bff; border-radius: 5px; transition: width 0.2s ease-in-out; }
        #ng-progress-text { text-align: center; margin-top: 5px; font-size: 12px; color: #d4d4d4; }
        #ng-modal-buttons { display: flex; justify-content: flex-end; gap: 10px; margin-top: 20px; flex-wrap: wrap; border-top: 1px solid #555; padding-top: 20px;}
        .ng-modal-btn { padding: 10px 20px; border: none; color: white; border-radius: 5px; cursor: pointer; }
        .btn-start { background-color: #28a745; }
        .btn-warning { background-color: #ffc107; color: black; }
        .btn-close { background-color: #6c757d; }
        .ng-checkbox-line { display: flex; align-items: center; margin-bottom: 10px; font-size: 1.1em; }
        .ng-checkbox-line label { flex-grow: 1; cursor: pointer; display: flex; align-items: center; }
        .ng-checkbox-line .count { font-style: italic; color: #aaa; margin-left: auto; padding-left: 20px; }
        .ng-checkbox-line input { margin-right: 15px; width: 18px; height: 18px; }
        #ng-select-all-line { border-bottom: 1px solid #555; padding-bottom: 15px; margin-bottom: 15px; }
    `);

    // ========================================================================
    // 2. ZENTRALE KONFIGURATION & MODUL-DATENBANK
    // ========================================================================
    const BATCH_SIZE = 15;
    const MARKER = '\u200B';

    Array.prototype.random = function() {
        return this[Math.floor(Math.random() * this.length)];
    };

    function joinWithSuffix(base, suffix) {
        if (suffix.startsWith('-')) {
            return `${base}${suffix}`;
        }
        return `${base} ${suffix}`;
    }

    const MODULE_CONFIG = {
        bergrettung: {
            name: "Bergrettung (Gipfelstürmer)", emoji: "🏔️",
            targetVehicleTypes: { 149: 'GW-Bergrettung (NEF)', 150: 'GW-Bergrettung', 151: 'ELW Bergrettung', 152: 'ATV', 154: 'Schneefahrzeug', 155: 'Anh Höhenrettung (Bergrettung)', 158: 'GW-Höhenrettung (Bergrettung)' },
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Gipfel-", "Gletscher-", "Alpen-", "Fels-", "Schnee-", "Eis-", "Gams-", "Stein-", "Höhen-", "Lawinen-", "Grat-", "Alm-"];
                const adjektive = ["Eisiger", "Steiler", "Schroffer", "Standfester", "Mutiger", "Schneidiger", "Alpiner", "Gipfelklarer", "Lawinensicherer", "Abgehärteter", "Erfahrener", "Trittsicherer"];
                const namen = [
                    "Reinhold Messner", "Luis Trenker", "Hermann Buhl", "Peter Habeler", "Gerlinde Kaltenbrunner", "Hans Kammerlander", "Ötzi", "Heidi", "Alm-Öhi", "Yeti", "Gletscher-Geist", "Der Bergdoktor", "Andreas Gabalier",
                    "Steinbock", "Gams", "Murmeltier", "Adler", "Geier", "Bernhardiner", "Alpen-Salamander", "Schneehase", "Steinadler", "Bartgeier", "Alpendohle", "Schneefink", "Kreuzotter", "Apollofalter", "Alpenbock",
                    "Mount Everest", "K2", "Mont Blanc", "Matterhorn", "Zugspitze", "Großglockner", "Eiger-Nordwand", "Dolomiten", "Watzmann", "Himalaya", "Anden", "Rocky Mountains", "Karakorum", "Pamir", "Kaukasus",
                    "Karabiner", "Eispickel", "Steigeisen", "Seilschaft", "Biwak", "Lawine", "Gletscherspalte", "Klettergurt", "Schneeschuh", "Pistenraupe", "Skidoo", "Quad", "Unimog", "Haglund",
                    "Gipfelkreuz", "Bergkristall", "Edelweiß", "Enzian", "Almrausch", "Gondel", "Sessellift", "Bergführer", "Hüttenwirt", "Sherpa", "Gipfelstürmer", "Alpinist", "Kletterer", "Wanderer",
                    "Gipfel-Taxi", "Latschenkiefer-Latscher", "Geröll-Gerümpel", "Wander-Wachtel", "Touristen-Retter", "Alpen-Sherpa", "Hüttenwirt-Helfer", "Verirrten-Verfolger", "Höhen-Krankheit", "Schnee-Schieber",
                    "Gletscher-Gondel", "Steinadler-Shuttle", "Sandalen-Sammler", "Flip-Flop-Finder", "Der letzte Lift", "Jodel-Diplom", "Murmeltier-Murks", "Gamsbart-Gondoliere", "Klettersteig-Klops",
                    "Lawinen-Loser-Lotsendienst", "Geröll-Römer", "Eis-Kratzer", "Absturz-Assistent", "Bruchharsch-Bezwinger", "Firn-Fahnder", "Schneebrett-Sheriff", "Spalten-Springer", "Überlebens-Übersetzer",
                    "Höhen-Rettungs-Held", "Anti-Absturz-Einheit", "Gipfel-Gigant", "Fels-Flüsterer", "Eis-Eroberer", "Schnee-Stapfer", "Grat-Wanderer", "Alm-Apostel", "Kraxel-Kommando", "Wand-Wächter",
                    "Seil-Spezialist", "Haken-Held", "Pickel-Pionier", "Steig-Eisen-Stratege", "Biwak-Bataillon", "Spalten-Schreck", "Gurt-Gott", "Pisten-Polizei", "Kristall-Kurier", "Edelweiß-Express",
                    "Enzian-Einsatz", "Hütten-Helfer", "Sherpa-Shuttle", "Gipfel-Gämse", "Gletscher-Goliath", "Fels-Fundament", "Eis-Titan", "Schnee-Sturm", "Alpen-Apostel", "Berg-Bulle", "Grat-Gigant",
                    "Wand-Wüterich", "Kletter-König", "Seil-Souverän", "Haken-Halbgott", "Pickel-Prinz", "Steig-Star", "Biwak-Boss", "Spalten-Spezi", "Gurt-Genie", "Pisten-Pate", "Kristall-Kaiser",
                    "Edelweiß-Elite", "Enzian-Eroberer", "Hütten-Hüne", "Sherpa-Star", "Gipfel-General", "Gletscher-Gebieter", "Fels-Fürst", "Eis-Imperator", "Schnee-Sultan", "Alpen-Admiral", "Berg-Baron",
                    "Grat-Gebieter", "Wand-Warlord", "Kletter-Kaiser", "Seil-Sultan", "Haken-Herrscher", "Pickel-Papst", "Steig-Souverän", "Biwak-Baron", "Spalten-Stratege", "Gurt-Gigant",
                    "Pisten-Präsident", "Kristall-König", "Edelweiß-Emir", "Enzian-Experte", "Hütten-Häuptling", "Sherpa-Scheich", "Alpen-Chaot", "Berg-Berserker", "Gipfel-Geist", "Gletscher-Gigant",
                    "Fels-Fanatiker", "Eis-Elefant", "Schnee-Schamane", "Grat-Guerilla", "Wand-Wahnsinniger", "Kletter-Kamikaze", "Seil-Samurai", "Haken-Haudegen", "Pickel-Pirat", "Steig-Stratege",
                    "Biwak-Biest", "Spalten-Schlächter", "Gurt-Guru", "Pisten-Pirat", "Kristall-Krieger", "Edelweiß-Ehrenmann", "Enzian-Entdecker", "Hütten-Held", "Sherpa-Spezialist", "Gipfel-Gladiator",
                    "Gletscher-Krieger", "Fels-Folterer", "Eis-Eremit", "Schnee-Schlächter", "Alpen-Ass", "Berg-Bestie", "Grat-Gott", "Wand-Wunder", "Kletter-Koryphäe", "Seil-Savant", "Haken-Heiland",
                    "Pickel-Professor", "Steig-Sensei", "Biwak-Büffel", "Spalten-Serpent", "Gurt-General", "Pisten-Phantom"
                ];
                const patterns = [() => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}`];
                return patterns.random()();
            }
        },
        hunde: {
            name: "Hundestaffel (Beste Spürnasen)", emoji: "🐕",
            targetVehicleTypes: { 91: 'Rettungshundefahrzeug', 92: 'Anh Hund', 94: 'DHuFüKW', 153: 'Hundestaffel (Bergrettung)' },
            largeVehicleIds: [153], // ID 153 ist unser "Sonderfall"
            nameGenerator: function(isLarge = false) {
                // Standard-Wortlisten für alle normalen Hunde
                const praefixe = ["Spürnasen-", "Fährten-", "Rettungs-", "Leckerli-", "Bello-", "Wuff-", "K-9-", "Hunde-", "Fellnasen-", "Pfoten-", "Knochen-"];
                const adjektive = ["Treuer", "Wachsamer", "Lauter", "Feiner", "Spitzfindiger", "Mutiger", "Verfressener", "Verspielter", "Heldenhafter", "Unbestechlicher", "Sabbernder", "Loyaler"];
                const substantive_hunde = ["Partner", "Kollege", "Wächter", "Spürnase", "Fährtensucher", "Retter", "Held", "Beschützer", "Ermittler", "Beißer", "Kläffer", "Helfer auf 4 Pfoten"];
                const namen = [
                    "Kommissar Rex", "Lassie", "Rin Tin Tin", "Toto", "Pluto", "Goofy", "Snoopy", "Beethoven", "Hachiko", "Balto", "Cerberus", "Scooby-Doo", "Struppi", "Idefix", "Barry",
                    "Buddy", "Chase", "Marshall", "Rocky", "Rubble", "Skye", "Zuma", "Everest", "Tracker", "Bolt", "Dug", "Pongo", "Perdita", "Slinky", "Santa's Little Helper", "Brian Griffin",
                    "Chance", "Shadow", "Milo", "Otis", "Copper", "Fang", "Max", "Gromit", "Odie", "Spike", "Tyke", "Droopy", "Huckleberry Hound", "Augie Doggie", "Muttley", "Scrappy-Doo",
                    "Marmaduke", "Underdog", "Clifford", "Blue", "Lady", "Tramp", "Jock", "Trusty", "Porky", "Rowlf", "Einstein", "Brutus", "Zero", "Winston", "Buck", "Marley", "Sam", "Benji",
                    "Schäferhund", "Malinois", "Rottweiler", "Bernhardiner", "Golden Retriever", "Labrador", "Spürhund", "Bluthund", "Dobermann", "Dalmatiner", "Beagle", "Border Collie",
                    "Dackel", "Husky", "Terrier", "Dogge", "Mastiff", "Schnauzer", "Boxer", "Akita", "Jack Russell", "Laika", "Greywind", "Nymeria", "Shaggydog",
                    "Fass", "Platz", "Sitz", "Apport", "Such", "Bleib", "Hier", "Fein", "Gib Laut", "Voran", "Aus", "Fuß", "Hopp", "Bring", "Steh", "Down", "Such und Hilf", "Revier", "Verbellen",
                    "Leckerli-Bomber", "Bello-Mobil", "Spürnasen-Express", "Fährten-Ferkel", "K-9-Kutsche", "Gebell-Gruppe", "Sabber-Shuttle", "Tatort-Taz", "Wadenbeißer-Wagen", "Fell-Geschoss",
                    "Alarm auf 4 Pfoten", "Der nasse Stupser", "Knochen-Jäger", "Postboten-Schreck", "Keksdieb-Kommando", "Anti-Katzen-Kommando", "Sofawolf-Shuttle", "Haufen-Finder", "Buddel-Bataillon",
                    "Streichel-Einheit", "Quietsche-Tier-Vernichter", "Sabber-Spezialist", "Futterneid-Flotte", "Stöckchen-Such-Service", "Platz-Polizei", "Sitz-Streife", "Bällchen-Junkie",
                    "Fehlalarm-Fifi", "Reste-Vertilger", "Lausch-Angriff", "Chaos-Charly", "Pfützen-Prüfer", "Schuh-Sortierer", "Fährten-Vernichter", "Bett-Besetzer"
                ];

                if (isLarge) { // HIER PASSIERT DIE MAGIE FÜR DEN SONDERFALL (ID 153)
                    const alpin_praefixe = ["Alpen-", "Gletscher-", "Lawinen-", "Gipfel-", "Firn-", "Geröll-", "Schnee-"];
                    const alpin_adjektive = ["Trittsicherer", "Schneefester", "Alpiner", "Kälte-resistenter"];
                    const alpin_namen = ["Lawinen-Wuff", "Alpen-Bello", "Gipfel-Kläffer", "Schnee-Schnauze", "Geröll-Retriever", "Yeti-Jäger", "Murmeltier-Melder", "Firn-Finder", "Barry der Held", "Heidi's Held", "Alm-Aportierer"];
                    const hybrid_patterns = [
                        () => alpin_namen.random(),
                        () => `${alpin_praefixe.random()}${substantive_hunde.random()}`,
                        () => `${alpin_adjektive.random()} ${substantive_hunde.random()}`,
                        () => `${alpin_adjektive.random()} ${namen.random()}`
                    ];
                    return hybrid_patterns.random()();
                } else { // Standard-Logik für alle anderen Hunde
                    const patterns = [
                        () => namen.random(),
                        () => `${adjektive.random()} ${substantive_hunde.random()}`,
                        () => `${praefixe.random()}${substantive_hunde.random()}`
                    ];
                    return patterns.random()();
                }
            }
        },
        pferde: {
            name: "Reiterstaffel (Hü-Hott-Express)", emoji: "🐎",
            targetVehicleTypes: { 134: 'Pferdetransporter klein', 135: 'Pferdetransporter groß', 136: 'Anh Pferdetransport', 137: 'Zugfahrzeug Pferdetransport' },
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Huf-", "Galopp-", "Reiter-", "Kavallerie-", "Stall-", "Koppel-", "Heu-", "Hafer-", "Sattel-", "Striegel-", "Pferdestärken-"];
                const adjektive = ["Stolzer", "Edler", "Wilder", "Schnaubender", "Trotziger", "Sanfter", "Anmutiger", "Ungezähmter", "Königlicher", "Schwerer", "Galoppierender", "Wiehernder"];
                const namen = [
                    "Fury", "Black Beauty", "Jolly Jumper", "Sleipnir", "Bucephalus", "Schattenfell", "Rocinante", "Seabiscuit", "Secretariat", "Hidalgo", "Pegasus", "Kleiner Onkel", "Bürger", "Amigo",
                    "Tornado", "Zorro", "Silver", "Trigger", "Champion", "Maximus", "Samson", "Philippe", "Khan", "Angus", "Bullseye", "Spirit", "Rain", "Artax", "Flicka", "Gunpowder", "Goliath",
                    "Incitatus", "Marengo", "Copenhagen", "Comanche", "Traveler", "Cincinnati", "Alcatraz", "Balthasar", "Ferdinand", "Valegro", "Totilas", "Donnerhall", "Ratina Z", "Milton",
                    "Hickstead", "Shutterfly", "For Pleasure", "Goldfever", "Gigolo", "Satchmo", "Bonfire", "Ahlerich", "Rembrandt", "Meteor", "Abdullah", "Salinero", "Cornet Obolensky", "Casall",
                    "Chacco-Blue", "Brego", "Arod", "Hasufel", "Roheryn", "Snowmane", "Windfola", "Blackie", "Sefton", "Sergeant Reckless", "Haflinger", "Friese", "Andalusier", "Shire Horse",
                    "Mustang", "Araber", "Lipizzaner", "Kaltblut", "Warmblut", "Vollblut", "Pinto", "Appaloosa", "Quarter Horse", "Paint Horse", "Tinker", "Noriker", "Percheron", "Holsteiner",
                    "Hannoveraner", "Oldenburger", "Westfale", "Trakehner", "Fjordpferd", "Isländer", "Hufschlag", "Galopp", "Trab", "Sattel", "Zaumzeug", "Pferdestärke", "Kutsche", "Kavallerie",
                    "Hafer-Moped", "Sheriff's-Mustang", "Heu-Transporter", "Stall-Geruch", "Laser-Pony", "Ein-PS-Einsatz", "Wiehernder-Wachtmeister", "Apfelschimmel-Alarm", "Einsatz-Einhorn",
                    "Zuckerwürfel-Zerstörer", "Möhren-Mafia", "Galoppierende-Gesetzeslage", "Trab-Titan", "Sattel-Sheriff", "Der Amtsschimmel", "Kaltblut-Kommando", "Vollblut-Vollstrecker",
                    "Huf-Hooligan", "Striegel-Streife", "Fliegende Mähne", "Gras-Antrieb", "Bio-Bulle", "Das letzte Einhorn", "Vierhufer-Vortrupp", "Heu-Highway-Patrol", "Koppel-Cop",
                    "Äppel-Produzent", "Fliegen-Schreck", "Staub-Aufwirbler", "Hindernis-Hasser", "Karotten-Kurier", "Panik-Pferd", "Gemüse-Vernichter", "Hengst", "Rappe", "Schimmel", "Fuchs", "Wallach", "Streitross", "Husar", "Ulan", "Dragoner", "Kürassier", "Zentaur", "Gaul"
                ];
                const patterns = [() => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}`];
                return patterns.random()();
            }
        },
        thw: {
            name: "THW (Die blauen Wichtel)", emoji: "🛠️",
            targetVehicleTypes: { 40: 'MTW-TZ', 41: 'MzGW (FGr N)', 42: 'LKW K 9', 43: 'BRmG R', 44: 'Anh DLE', 45: 'MLW 5', 93: 'MTW-O', 100: 'MLW 4', 101: 'Anh SwPu', 102: 'Anh 7', 109: 'MzGW SB', 122: 'LKW 7 Lbw (FGr E)', 123: 'LKW 7 Lbw (FGr WP)', 124: 'MTW-OV' },
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Technik-", "Hilfs-", "Bau-", "Logistik-", "Räum-", "Stütz-", "Pumpen-", "Generator-", "Blau-", "Wichtel-", "Chaos-", "Paletten-", "Kabel-", "Schlumpf-", "Trümmer-", "Beton-", "Holz-", "Stahl-"];
                const adjektive = ["Blauer", "Technischer", "Hilfsbereiter", "Verplanter", "Chaotischer", "Stabiler", "Schwerer", "Tragender", "Leuchtender", "Unermüdlicher", "Kreativer", "Solider", "Standfester", "Robuster"];
                const namen = [
                    "Wichtel", "Schlumpf", "Helfer", "Pionier", "Logistiker", "Ingenieur", "Baumeister", "Maschinist", "Anpacker", "Fachberater", "Ortsbeauftragter", "Bastler", "Tüftler", "Konstrukteur", "Statiker", "Truppführer", "Baufachberater",
                    "Kraftfahrer", "Baukasten", "Stütze", "Fundament", "Generator", "Pumpe", "Hebel", "Getriebe", "Werkzeugkiste", "Palette", "Gitterbox", "Einsatzbefehl", "Lichtmast", "Strom-Aggregat", "Presslufthammer",
                    "Trennschleifer", "Hydraulik-Spreizer", "Betonkettensäge", "Stahlträger", "Sandsack", "Tauchpumpe", "Notstromaggregat", "Hebekissen", "Kernbohrgerät", "Plasmabrenner", "Verbrauchsgut", "Abstützung",
                    "Hochwasser-Helfer", "Sturmschaden-Beseitiger", "Blaue-Eminenz", "Chaos-Kommando", "Wichtel-Express", "Technik-Trouble", "Paletten-Polo", "Kabel-Salat-Express", "Schlumpf-Transporter", "Hüpfburg-Aufbauer",
                    "Kaffee-Versorger", "THW-Taxi", "Tausend-Hilflose-Wichtel", "Toll-ein-Anderer-Machts", "Teile-Hin-und-Weg", "Legoland-für-Erwachsene", "Gitterbox-Ballett", "Katastrophen-Touristen-Betreuung",
                    "Unter Helfersyndrom Leidende", "Blaulicht-Tetris", "Deich-Verteidiger", "Keller-Leer-Pumper", "Sandsack-Schlepper-Syndikat", "Stapel-Stratege", "Überall-Helfer", "Ich-kann-das-reparieren",
                    "Der-Gerade-Bieger", "Blauer Engel mit Werkzeugkoffer", "Katastrophen-Kaffeekränzchen", "Stapel-Champion", "Alles-Kleber", "Gaffer-Abschirmung", "Strom-Dealer", "Licht-Bringer", "Pumpen-Paganini",
                    "Räum-Rambo", "Stütz-Stalin", "Logistik-Lord", "Bau-Baron", "Technik-Titan", "Hilfs-Held", "Wichtel-Wunder", "Schlumpf-Sheriff", "Trümmer-Troll", "Beton-Beißer", "Holz-Hobbit", "Stahl-Stier",
                    "Paletten-Papst", "Kabel-König", "Generator-Genie", "Stapel-Sultan", "Universal-Dilettant", "Hoffnung in Blau", "Technik die begeistert", "Wo ist die Anleitung?", "Ehrenamts-Einhorn",
                    "Material-Magier", "Feld-Faktotum", "Not-Nagel", "Krisen-Künstler", "Lage-Löser", "Problem-Pflaster", "Sorgen-Schlichter", "Unwetter-Uhu", "Sturm-Stratege", "Flut-Flüsterer", "Chaos-Chirurg",
                    "Pannen-Pionier", "Rettungs-Ritter", "Hilfs-Heiland", "Technik-Teufel", "Blauer Riese", "Der Zupacker", "Der Macher", "Der Kümmerer", "Die Hoffnung", "Der Fels in der Brandung", "Der Alleskönner",
                    "Das Schweizer Taschenmesser", "Der Problemlöser", "Der Unverzichtbare", "Der Held vom Erdbeerfeld", "Der letzte Ausweg", "Der Joker", "Die blaue Wand", "Der Fels", "Der Anker", "Der Leuchtturm", "Der Felsblock",
                    "Die Stütze der Gesellschaft", "Der blaue Blitz", "Der blaue Donner", "Der blaue Sturm", "Der blaue Orkan", "Der blaue Tsunami", "Der blaue Vulkan", "Der blaue Komet", "Der blaue Meteor",
                    "Der blaue Gigant", "Der blaue Titan", "Der blaue Koloss", "Der blaue Goliath", "Der blaue Herkules", "Der blaue Samson", "Der blaue Atlas", "Der blaue Odysseus", "Der blaue Achilles", "Der blaue Hektor"
                ];
                const patterns = [ () => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}` ]; return patterns.random()(); }
        },
        betreuung: {
            name: "Betreuung & Verpflegung", emoji: "🍲",
            targetVehicleTypes: { 130: 'GW-Bt', 131: 'Bt-Kombi', 132: 'FKH', 133: 'Bt LKW', 138: 'GW-Verpflegung', 139: 'GW-Küche', 140: 'MTW-Verpflegung', 141: 'FKH', 142: 'AB-Küche' },
            nameGenerator: function(isLarge = false) {
                const gerichte = [
                    { name: "Aal Grün", gender: "m" }, { name: "Aalsuppe", gender: "f" }, { name: "Adana Kebab", gender: "m" }, { name: "Ahi-Thunfisch-Steak", gender: "n" },
                    { name: "Ajvar", gender: "n" }, { name: "Allgäuer Kässpatzen", gender: "p" }, { name: "Amerikaner", gender: "p" }, { name: "Apfel im Schlafrock", gender: "m" },
                    { name: "Apfelmus", gender: "n" }, { name: "Apfelpfannkuchen", gender: "m" }, { name: "Apfelstrudel", gender: "m" }, { name: "Arme Ritter", gender: "p" },
                    { name: "Arrabiata", gender: "f" }, { name: "Artischocke", gender: "f" }, { name: "Asiatische Nudelpfanne", gender: "f" }, { name: "Aspik", gender: "n" },
                    { name: "Aubergine", gender: "f" }, { name: "Auflauf", gender: "m" }, { name: "Austern", gender: "p" }, { name: "Baba Ghanoush", gender: "n" },
                    { name: "Backfisch", gender: "m" }, { name: "Backkartoffel", gender: "f" }, { name: "Bacon Bomb", gender: "f" }, { name: "Baguette", gender: "n" },
                    { name: "Bami Goreng", gender: "n" }, { name: "Bananenbrot", gender: "n" }, { name: "Bärlauchsuppe", gender: "f" }, { name: "Bauernfrühstück", gender: "n" },
                    { name: "Bayerischer Wurstsalat", gender: "m" }, { name: "Beef Brisket", gender: "n" }, { name: "Beef Wellington", gender: "n" }, { name: "Beignet", gender: "m" },
                    { name: "Berliner", gender: "p" }, { name: "Bienenstich", gender: "m" }, { name: "Bigos", gender: "n" }, { name: "Birnen, Bohnen und Speck", gender: "p" },
                    { name: "Bismarckhering", gender: "m" }, { name: "Blini", gender: "p" }, { name: "Blumenkohl", gender: "m" }, { name: "Blutwurst", gender: "f" },
                    { name: "Bockwurst", gender: "f" }, { name: "Boeuf Bourguignon", gender: "n" }, { name: "Bohneneintopf", gender: "m" }, { name: "Bolognese", gender: "f" },
                    { name: "Borscht", gender: "m" }, { name: "Bouillabaisse", gender: "f" }, { name: "Bratapfel", gender: "m" }, { name: "Bratensoße", gender: "f" },
                    { name: "Bratkartoffeln", gender: "p" }, { name: "Bratwurst", gender: "f" }, { name: "Brezel", gender: "f" }, { name: "Brokkoli", gender: "m" },
                    { name: "Brownie", gender: "m" }, { name: "Bruschetta", gender: "f" }, { name: "Bulette", gender: "f" }, { name: "Bulgursalat", gender: "m" },
                    { name: "Burger", gender: "m" }, { name: "Burrito", gender: "m" }, { name: "Butterbrot", gender: "n" }, { name: "Calzone", gender: "f" },
                    { name: "Cannelloni", gender: "p" }, { name: "Caprese", gender: "f" }, { name: "Carbonara", gender: "f" }, { name: "Cevapcici", gender: "p" },
                    { name: "Cheesecake", gender: "m" }, { name: "Chicken Nuggets", gender: "p" }, { name: "Chicken Wings", gender: "p" }, { name: "Chili con Carne", gender: "n" },
                    { name: "Chili sin Carne", gender: "n" }, { name: "Churros", gender: "p" }, { name: "Clubsandwich", gender: "n" }, { name: "Coleslaw", gender: "m" },
                    { name: "Corn Dog", gender: "m" }, { name: "Couscous", gender: "m" }, { name: "Crème brûlée", gender: "f" }, { name: "Crepes", gender: "p" },
                    { name: "Crostini", gender: "p" }, { name: "Crumble", gender: "m" }, { name: "Currywurst", gender: "f" }, { name: "Dal", gender: "n" },
                    { name: "Dampfnudel", gender: "f" }, { name: "Döner Kebab", gender: "m" }, { name: "Donut", gender: "m" }, { name: "Dürüm", gender: "m" },
                    { name: "Eier im Glas", gender: "p" }, { name: "Eierkuchen", gender: "m" }, { name: "Eiersalat", gender: "m" }, { name: "Eintopf", gender: "m" },
                    { name: "Eisbein", gender: "n" }, { name: "Empanada", gender: "f" }, { name: "Enchilada", gender: "f" }, { name: "Erbsensuppe", gender: "f" },
                    { name: "Erdbeerkuchen", gender: "m" }, { name: "Fajita", gender: "f" }, { name: "Falafel", gender: "p" }, { name: "Falscher Hase", gender: "m" },
                    { name: "Feuerflecken", gender: "m" }, { name: "Finanztopf", gender: "m" }, { name: "Fish and Chips", gender: "p" }, { name: "Flammkuchen", gender: "m" },
                    { name: "Frikadelle", gender: "f" }, { name: "Frühlingsrolle", gender: "f" }, { name: "Gaisburger Marsch", gender: "m" }, { name: "Garnelen", gender: "p" },
                    { name: "Gazpacho", gender: "f" }, { name: "Gebratene Nudeln", gender: "p" }, { name: "Gefillde", gender: "p" }, { name: "Gemüseauflauf", gender: "m" },
                    { name: "Gemüsepfanne", gender: "f" }, { name: "Germknödel", gender: "m" }, { name: "Geschnetzeltes", gender: "n" }, { name: "Gnocchi", gender: "p" },
                    { name: "Grießbrei", gender: "m" }, { name: "Grillhähnchen", gender: "n" }, { name: "Grünkohl mit Pinkel", gender: "m" }, { name: "Gulasch", gender: "n" },
                    { name: "Gulaschkanone", gender: "f" }, { name: "Gurkensalat", gender: "m" }, { name: "Gyros", gender: "n" }, { name: "Hackbraten", gender: "m" },
                    { name: "Hähnchencurry", gender: "n" }, { name: "Halloumi", gender: "m" }, { name: "Hamburger", gender: "m" }, { name: "Handkäse mit Musik", gender: "m" },
                    { name: "Haxe", gender: "f" }, { name: "Hefekloß", gender: "m" }, { name: "Heringssalat", gender: "m" }, { name: "Himmel un Ääd", gender: "n" },
                    { name: "Hot Dog", gender: "m" }, { name: "Hummus", gender: "m" }, { name: "Jägerschnitzel", gender: "n" }, { name: "Jambalaya", gender: "f" },
                    { name: "Kaiserschmarrn", gender: "m" }, { name: "Käsekuchen", gender: "m" }, { name: "Käsespätzle", gender: "p" }, { name: "Kassler", gender: "n" },
                    { name: "Kartoffelpuffer", gender: "p" }, { name: "Kartoffelsalat", gender: "m" }, { name: "Kartoffelsuppe", gender: "f" }, { name: "Kebab", gender: "m" },
                    { name: "Königsberger Klopse", gender: "p" }, { name: "Köttbullar", gender: "p" }, { name: "Krautwickel", gender: "p" }, { name: "Krapfen", gender: "m" },
                    { name: "Labskaus", gender: "n" }, { name: "Lahmacun", gender: "f" }, { name: "Lasagne", gender: "f" }, { name: "Leberkäse", gender: "m" },
                    { name: "Linseneintopf", gender: "m" }, { name: "Mac and Cheese", gender: "n" }, { name: "Maultaschen", gender: "p" }, { name: "Mettbrötchen", gender: "n" },
                    { name: "Milchreis", gender: "m" }, { name: "Minestrone", gender: "f" }, { name: "Moussaka", gender: "n" }, { name: "Mozzarella-Sticks", gender: "p" },
                    { name: "Muffin", gender: "m" }, { name: "Muscheln", gender: "p" }, { name: "Nasi Goreng", gender: "n" }, { name: "Nudelauflauf", gender: "m" },
                    { name: "Nudelsalat", gender: "m" }, { name: "Obatzda", gender: "m" }, { name: "Ochsenschwanzsuppe", gender: "f" }, { name: "Onion Rings", gender: "p" },
                    { name: "Pad Thai", gender: "n" }, { name: "Paella", gender: "f" }, { name: "Pannfisch", gender: "m" }, { name: "Panna Cotta", gender: "f" },
                    { name: "Peking-Ente", gender: "f" }, { name: "Pellkartoffeln mit Quark", gender: "p" }, { name: "Pesto", gender: "n" }, { name: "Pfannkuchen", gender: "m" },
                    { name: "Pfefferpotthast", gender: "m" }, { name: "Pho", gender: "f" }, { name: "Pichelsteiner", gender: "m" }, { name: "Pierogi", gender: "p" },
                    { name: "Pita", gender: "f" }, { name: "Pizza", gender: "f" }, { name: "Pizzabrötchen", gender: "p" }, { name: "Polenta", gender: "f" },
                    { name: "Pommes Frites", gender: "p" }, { name: "Porridge", gender: "n" }, { name: "Pulled Pork", gender: "n" }, { name: "Quesadilla", gender: "f" },
                    { name: "Quiche", gender: "f" }, { name: "Raclette", gender: "n" }, { name: "Rahmschnitzel", gender: "n" }, { name: "Ramen", gender: "m" },
                    { name: "Ratatouille", gender: "n" }, { name: "Ravioli", gender: "p" }, { name: "Reibekuchen", gender: "m" }, { name: "Rinderroulade", gender: "f" },
                    { name: "Risotto", gender: "n" }, { name: "Rollmops", gender: "m" }, { name: "Rote Grütze", gender: "f" }, { name: "Roulade", gender: "f" },
                    { name: "Rührei", gender: "n" }, { name: "Samosa", gender: "f" }, { name: "Saumagen", gender: "m" }, { name: "Sauerbraten", gender: "m" },
                    { name: "Sauerkraut", gender: "n" }, { name: "Schaschlik", gender: "n" }, { name: "Schichtkohl", gender: "m" }, { name: "Schlachtplatte", gender: "f" },
                    { name: "Schnitzel", gender: "n" }, { name: "Schupfnudeln", gender: "p" }, { name: "Schwarzwälder Kirschtorte", gender: "f" }, { name: "Schweinshaxe", gender: "f" },
                    { name: "Semmelknödel", gender: "m" }, { name: "Senfeier", gender: "p" }, { name: "Serbische Bohnensuppe", gender: "f" }, { name: "Shakshuka", gender: "f" },
                    { name: "Shepherd's Pie", gender: "m" }, { name: "Soljanka", gender: "f" }, { name: "Sommerrolle", gender: "f" }, { name: "Spaghetti", gender: "p" },
                    { name: "Spargel", gender: "m" }, { name: "Spätzle", gender: "p" }, { name: "Spiegelei", gender: "n" }, { name: "Spinat", gender: "m" },
                    { name: "Steak", gender: "n" }, { name: "Strammer Max", gender: "m" }, { name: "Strudel", gender: "m" }, { name: "Sülze", gender: "f" },
                    { name: "Sushi", gender: "n" }, { name: "Taboulé", gender: "n" }, { name: "Taco", gender: "m" }, { name: "Tafelspitz", gender: "m" },
                    { name: "Tagliatelle", gender: "p" }, { name: "Tandoori Chicken", gender: "n" }, { name: "Tapas", gender: "p" }, { name: "Tartar", gender: "n" },
                    { name: "Tarte", gender: "f" }, { name: "Thüringer Klöße", gender: "p" }, { name: "Tiramisu", gender: "n" }, { name: "Toast Hawaii", gender: "m" },
                    { name: "Tofu", gender: "m" }, { name: "Tomatensuppe", gender: "f" }, { name: "Tortellini", gender: "p" }, { name: "Tsatsiki", gender: "n" },
                    { name: "Udon-Nudeln", gender: "p" }, { name: "Vitello Tonnato", gender: "n" }, { name: "Waffel", gender: "f" }, { name: "Weißwurst", gender: "f" },
                    { name: "Westfälische Rinderwurst", gender: "f" }, { name: "Wiener Schnitzel", gender: "n" }, { name: "Wirsing", gender: "m" }, { name: "Wurstgulasch", gender: "n" },
                    { name: "Wurstsalat", gender: "m" }, { name: "Zigeunerschnitzel", gender: "n" }, { name: "Zürcher Geschnetzeltes", gender: "n" }, { name: "Zwiebelkuchen", gender: "m" }
                ];
                const praefixe = ["Rollende", "Mobile", "Heisse", "Feld-", "Einsatz-", "Taktische", "Herzhafte", "Seelen-", "Wohlfühl-", "Mampf-", "Deftige"];
                const suffixe = ["Bude", "Express", "Grill", "Mobil", "Eck", "Hütte", "Kelle", "Pfanne", "Topf", "Küche", "Versorgung", "Oase", "Kombüse", "Station"];
                const personen = ["Smutje", "Küchenchef", "Kombüsen-König", "Suppen-Kasper", "Grillmeister", "Brutzler", "Feldkoch"];
                const humor = ["Futter-Krippe", "Magen-Füller", "Geschmacks-Explosion", "Kalorien-Bomber", "Seelentröster", "Moral-Heber", "Katerfrühstück", "Nervennahrung"];

                while (true) {
                    const gewaehlterTyp = ['praefix_kombi', 'suffix_kombi', 'tour_kombi', 'heiss_kombi', 'lecker_kombi', 'funktion_kombi'].random();
                    const gericht = gerichte.random();

                    switch (gewaehlterTyp) {
                        case 'praefix_kombi':
                            return `${praefixe.random()} ${gericht.name}`;
                        case 'suffix_kombi':
                            return `${gericht.name}-${suffixe.random()}`;
                        case 'tour_kombi':
                            return `${gericht.name} on Tour`;
                        case 'heiss_kombi':
                            if (gericht.gender === 'p') continue; // Skip plural for this pattern
                            switch (gericht.gender) {
                                case 'm': return `Heißer ${gericht.name}`;
                                case 'f': return `Heiße ${gericht.name}`;
                                case 'n': return `Heißes ${gericht.name}`;
                            }
                            break;
                        case 'lecker_kombi':
                            if (gericht.gender === 'p') continue; // Skip plural for this pattern
                            switch (gericht.gender) {
                                case 'm': case 'n': return `Zum leckeren ${gericht.name}`;
                                case 'f': return `Zur leckeren ${gericht.name}`;
                            }
                            break;
                        case 'funktion_kombi':
                            // This new case generates names NOT based on specific dishes
                            const subTyp = ['person', 'humor'].random();
                            if (subTyp === 'person') {
                                return `${praefixe.random()} ${personen.random()}`;
                            } else {
                                return `${humor.random()}-${suffixe.random()}`;
                            }
                    }
                }
            }
        },
        feuerwehr: {
            name: "Feuerwehr (Löschfahrzeuge)", emoji: "🔥",
            targetVehicleTypes: { 0: 'LF 20', 1: 'LF 10', 6: 'LF 8/6', 7: 'LF 20/16', 8: 'LF 10/6', 9: 'LF 16-TS', 17: 'TLF 2000', 18: 'TLF 3000', 19: 'TLF 8/8', 20: 'TLF 8/18', 21: 'TLF 16/24-Tr', 22: 'TLF 16/25', 23: 'TLF 16/45', 24: 'TLF 20/40', 25: 'TLF 20/40-SL', 26: 'TLF 16', 30: 'HLF 20', 37: 'TSF-W', 75: 'FLF', 84: 'ULF mit Löscharm', 86: 'Turbolöscher', 87: 'TLF 4000', 88: 'KLF', 89: 'MLF', 90: 'HLF 10', 107: 'LF-L', 121: 'GTLF', 166: 'PTLF 4000', 167: 'SLF' },
            largeVehicleIds: [121, 75, 87, 24, 25],
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Feuer-", "Brand-", "Lösch-", "Wasser-", "Hydro-", "Sturm-", "Blitz-", "Donner-", "Glut-", "Inferno-", "Flut-", "Höllen-", "Vulkan-", "Magma-", "Asche-", "Pyro-", "Rauch-"];
                const adjektive = ["Roter", "Wilder", "Zorniger", "Rasender", "Stählerner", "Mächtiger", "Brüllender", "Nasser", "Mutiger", "Tapferer", "Heldenhafter", "Göttlicher", "Legendärer", "Glühender", "Sengender", "Unbezwingbarer", "Stoischer", "Unaufhaltsamer", "Elementarer", "Donnernder", "Brachialer", "Zischender", "Eiskalter", "Massiver"];
                const namen = [
                    "Bulle", "Bär", "Eber", "Drache", "Walross", "Nashorn", "Elefant", "Mammut", "Dachs", "Titan", "Gigant", "Zyklop", "Held", "Goliath", "Thor", "Poseidon", "Krieger", "Barbar", "Wächter",
                    "Retter", "Jäger", "Bezwinger", "Hydra", "Cerberus", "Phoenix", "Balrog", "Hephaistos", "Erlöser", "Frontbrecher", "Behemoth", "Moloch", "Leviathan", "Ifrit", "Salamander", "Prometheus", "Vulkan",
                    "Surtr", "Loki", "Agni", "Ra", "Fafnir", "Basilisk", "Hammer", "Amboss", "Klinge", "Speer", "Faust", "Kolben", "Komet", "Meteor", "Gletscher", "Fels", "Bohrer", "Pflug", "Ramme", "Brecher", "Generator", "Reaktor", "Turbine",
                    "Lawine", "Tsunami", "Orkan", "Wellenbrecher", "Hydroschild", "Wasserwerfer", "Monitor", "Strahlrohr", "Halligan-Tool", "Flammpunkt", "Rauchgrenze", "Hitzeschild", "Maschinist", "Atemschutzträger",
                    "Flashover", "Backdraft", "Hohlstrahlrohr", "Zumischer", "Riegelstellung", "Innenangriff", "Rettungsplattform", "Sprungpolster",
                    "Wasser Marsch", "Pyromanen-Schreck", "Grill-Meister", "BMA-Tourist", "Keller-Ausleuchter", "Bäumchen-Bewässerer", "Katzen-Retter", "Leiter-Halter", "Schlauch-Salat",
                    "Tatü-Tata", "Blaulicht-Ballett", "Feuer-Fighter", "Glut-Goliath", "Nasser-Albtraum", "Heißmacher", "Durst-Löscher", "Party-Pumpe", "Schaum-Schläger", "Asphalt-Kühler",
                    "Tankstellen-Tester", "Hydranten-Hengst", "Letzte-Ölung", "Feuerteufel-Flüsterer", "Rauch-Ramme", "Wasser-Verschwender", "Grill-Aufsicht", "Wasserrechnungs-Treiber", "Mülleimerbrand-Spezialist",
                    "Funken-Fänger", "Zünd-Zerstörer", "Hitze-Held", "Flammen-Fresser", "Glut-Garant", "Asche-Artist", "Ruß-Ritter", "Qualm-Quälgeist", "Brand-Baron", "Lösch-Lord", "Feuer-Wall", "Flammen-Woge", "Wasser-Wand",
                    "Glut-Hölle", "Asche-Regen", "Rauch-Schwade", "Brand-Bestie", "Feuer-Orkan", "Flammen-Tsunami", "Wasser-Gewalt", "Glut-Sturm", "Asche-Sturm", "Rauch-Bestie", "Brand-Drache", "Feuer-Hydra",
                    "Flammen-Cerberus", "Wasser-Titan", "Glut-Gigant"
                ];
                const patterns = [() => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}`];
                let baseName = patterns.random()();
                if (isLarge) { baseName = joinWithSuffix(baseName, ["Gigant", "Koloss", "Titan", "Goliath", "Leviathan"].random()); }
                return baseName;
            }
        },
        polizei: {
            name: "Polizei (Basis-Einheiten)", emoji: "🚓",
            targetVehicleTypes: { 32: 'FuStW', 95: 'Polizeimotorrad', 50: 'GruKw', 52: 'GefKw' },
            largeVehicleIds: [52, 50],
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Streifen-", "Einsatz-", "Alarm-", "Zivil-", "Sonder-", "Verfolgungs-", "Fahndungs-", "Razzia-", "Blaulicht-", "Beweis-", "Zugriffs-", "Observierungs-", "Protokoll-", "Paragraphen-", "Sicherungs-", "Abschnitts-", "Kripo-", "Soko-"];
                const adjektive = ["Strenger", "Wachsamer", "Schneller", "Unbestechlicher", "Eiserner", "Gesetzestreuer", "Müder", "Harter", "Cooler", "Kompromissloser", "Unerbittlicher", "Hartnäckiger", "Präziser", "Observierender", "Schlafloser", "Bürokratischer", "Unnachgiebiger", "Verdeckter", "Ermittelnder"];
                const namen = [
                    "Gesetzeshüter", "Wachtmeister", "Kommissar", "Ermittler", "Sheriff", "Richter", "Ordnungshüter", "Fahnder", "Detektiv", "Spürhund", "Adlerauge", "Inspektor", "Marshall", "Vollstrecker", "Wächter",
                    "Kopfgeldjäger", "Spürfuchs", "Wachhund", "Bluthund", "Habicht", "Hauptmeister", "Zivilfahnder", "Asphalt-Cowboy", "Profiler", "Schatten", "Ermittlungsrichter", "Staatsanwalt", "Kriminaltechniker",
                    "Haftbefehl", "Alibi", "Protokoll", "Indiz", "Ermittlungsakte", "Rapport", "Zeugenaussage", "Täterprofil", "Gerechtigkeit", "Ordnung", "Gesetz", "Prävention", "Strafprozessordnung", "Eilverfahren", "Platzverweis",
                    "Diebstahl", "Betrug", "Nötigung", "Zeugenvernehmung", "Funkdisziplin", "Lagebild", "Schutzweste", "Bodycam", "Radarpistole", "Alkomat", "Spurensicherungskoffer", "Strafantrag", "Sicherstellung", "Personalienfeststellung",
                    "Donut-Vernichter", "Kaffee-Kocher", "Strafzettel-Baron", "Knöllchen-König", "Akten-Schlepper", "Kaffee-Junkie", "Donut-Inspektor", "Feierabend-Jäger", "Blitzer-Baron",
                    "Krapfen-Kommando", "Schicht-Schieber", "Verkehrs-Sünder-Schreck", "Dienst-nach-Vorschrift-Mobil", "Berufsverkehr-Bremser", "Paragraphen-Pirat", "Bürokratie-Beschleuniger", "Falschparker-Feind",
                    "Gähn-Geselle", "Warte-Wachtmeister", "Notizblock-Nervensäge", "Freund und Helfer", "Verwarnungs-Verteiler", "Mängel-Melder", "Streber-Streife", "Amtsmüder Augenzeuge", "Protokoll-Poet", "Donut-Dynamo",
                    "Schicht-Ende-Sehnsucht", "Kaffee-Kommando", "Ordnungs-Macht", "Rechts-Staat", "Schutz-Schild", "Sicherheits-Garant", "Präsenz-Profi", "Streifen-Stratege", "Einsatz-Experte", "Sherlock Holmes", "Dr. Watson",
                    "Hercule Poirot", "Miss Marple", "Philip Marlowe", "Sam Spade", "Columbo", "Kojak", "Derrick", "Schimanski", "Bulle von Tölz", "Tatort-Reiniger", "CSI", "NCIS", "FBI", "BKA", "LKA", "Interpol"
                ];
                const patterns = [() => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}`];
                let baseName = patterns.random()();
                if (isLarge) { baseName = `${baseName} ${["(Transport)", "(Schwerlast)", "(Zellenblock)", "(Mannschaft)"].random()}`; }
                return baseName;
            }
        },
        spezialeinheiten: {
            name: "Spezialeinheiten (SEK/MEK)", emoji: "💀",
            targetVehicleTypes: { 79: 'SEK - ZF', 80: 'SEK - MTF', 81: 'MEK - ZF', 82: 'MEK - MTF' },
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Zugriffs-", "Taktik-", "Schatten-", "Sturm-", "Alpha-", "Omega-", "Nacht-", "Kobra-", "Phantom-", "Kommando-", "Delta-", "Zero-", "Stahl-", "Titan-", "Wolfs-"];
                const adjektive = ["Stiller", "Präziser", "Eiserner", "Scharfer", "Chirurgischer", "Unerbittlicher", "Kompromissloser", "Getarnter", "Gepanzerter", "Lautloser", "Skrupelloser", "Finaler", "Letzter"];
                const namen = [
                    "Jäger", "Greifer", "Vollstrecker", "Brecher", "Phantom", "Schatten", "Operator", "Kommando", "Scharfschütze", "Geist", "Henker", "Wächter", "Wolf", "Hyäne", "Schakal", "Viper", "Kobra", "Cerberus",
                    "Nighthawk", "Valkyrie", "Chimäre", "Mantikor", "Gorgone", "Hydra", "Spectre", "Reaper", "Pointman", "Breacher", "GSG 9", "SAS", "Spetsnaz", "GIGN", "Navy Seal", "KSK", "Nemesis", "Thanatos",
                    "Ares", "Charon", "Styx", "Hades", "Anubis", "Zugriff", "Observation", "Belagerung", "Sturm", "Sicherung", "Eskorte", "Protokoll-Omega", "Letzte-Instanz", "Vergeltung", "Furcht",
                    "Zugriffs-Korridor", "Observationsteam", "Silent Entry", "Room Clearing", "Projekt Cerberus", "Operation Nachtnebel",
                    "Böser Onkel", "Tür-Eintreter", "Verhandlungs-Verweigerer", "Fenster-Gucker", "Pizza-Besteller", "Nachtschattengewächs", "Leisetreter", "Ramme-Ramme", "Poltergeist", "Wand-Wackler",
                    "Party-Crasher", "Überraschungsgast", "Spaß-Bremse", "Fenster-Einklatscher", "Adrenalin-Junkie", "Lautlos-Lurker", "Tango-Down-Team", "Schwarze-Witwe", "Höllen-Hund", "Stahl-Faust",
                    "Bitte nicht stören", "Klopfen war gestern", "Nihilist", "Stoiker", "Alpha", "Bravo", "Charlie", "Delta", "Echo", "Foxtrot", "Golf", "Hotel", "India", "Juliett", "Kilo", "Lima", "Mike",
                    "November", "Oscar", "Papa", "Quebec", "Romeo", "Sierra", "Tango", "Uniform", "Victor", "Whiskey", "X-Ray", "Yankee", "Zulu"
                ];
                const patterns = [() => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}`];
                return patterns.random()();
            }
        },
        rettung: {
            name: "Rettungsdienst (Basis-Einheiten)", emoji: "🚑",
            targetVehicleTypes: { 28: 'RTW', 73: 'GRTW', 29: 'NEF', 74: 'NAW', 38: 'KTW', 58: 'KTW Typ B' },
            largeVehicleIds: [73],
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Notfall-", "Rettungs-", "Pflaster-", "Pillen-", "Blaulicht-", "Kaffee-", "Herz-", "Klinik-", "Intensiv-", "Trauma-", "EKG-", "Defi-", "Adrenalin-", "Lebens-", "Aua-"];
                const adjektive = ["Schneller", "Eiliger", "Müder", "Geduldiger", "Piepsender", "Desinfizierter", "Lebensrettender", "Stabiler", "Ruhiger", "Hektischer", "Pulsierender", "Steriler", "Diagnostischer", "Beruhigender"];
                const namen = [
                    "Samariter", "Lebensretter", "Schutzengel", "Notarzt", "Sanitäter", "Ersthelfer", "Chirurg", "Anästhesist", "Erstversorger", "Schutzpatron", "Weißer Ritter", "Desinfektor", "Seelentröster", "Florence Nightingale", "Robert Koch", "Ignaz Semmelweis",
                    "Puls", "Trauma-Team", "Diagnose", "Lebensfunke", "Hoffnung", "Zweite-Chance", "Adrenalin-Stoß", "Infusion", "Venenkatheter", "Herzkammer", "Aorta", "Sinusknoten", "Stethoskop", "Blutdruck-Manager",
                    "EKG-Schreiber", "Defibrillator", "Atropin", "Intubation", "Thoraxdrainage", "Glukose", "Schockraum", "Intensivstation", "Vakuummatratze", "Schaufeltrage", "Anaphylaxie",
                    "Pillen-Taxi", "Aua-Wagen", "Schnupfen-Express", "Blaulicht-Bote", "Herzensbrecher", "Schock-Therapeut", "Kaffee-Kurier", "Pulsschubser", "Husten-Taxi", "Männer-Schnupfen-Mobil",
                    "Jammer-Lappen-Jäger", "Wehwehchen-Wagen", "Hypochonder-Heiland", "Bettenschubser", "Asphalt-Ambulanz", "Heftpflaster-Held", "Kaffee-Infusion", "Legebatterie", "Simulanten-Scanner",
                    "Aspirin-Apostel", "RTW-Chauffeur", "Pflaster-Kleber", "Diagnose-Dilettant", "Simulanten-Schreck", "Husten-Held", "Schnupfen-Sheriff", "Fieber-Fighter", "Kopfweh-Kavalier",
                    "Papierschnitt-Panik", "Männergrippe-Märtyrer", "Hypochonder-Hotline", "Placebo-Patrouille", "Krankenschein-Kurier", "Rettungs-Rambo", "Notfall-Nanny", "Blaulicht-Baron"
                ];
                const patterns = [() => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}`];
                let baseName = patterns.random()();
                if (isLarge) { baseName = `${baseName} ${["Klinik-Shuttle", "Maxi-Ambulanz", "Betten-Transporter", "Katastrophen-Helfer"].random()}`; }
                return baseName;
            }
        },
        fuehrung: {
            name: "Führungsfahrzeuge (Chef-Kutschen)", emoji: "👑",
            targetVehicleTypes: { 3: 'ELW 1', 34: 'ELW 2', 55: 'KdoW-LNA', 56: 'KdoW-OrgL', 35: 'leBefKw', 128: 'ELW Drohne', 129: 'ELW2 Drohne', 144: 'FüKW (THW)', 145: 'FüKomKW', 146: 'Anh FüLa', 147: 'FmKW', 148: 'MTW-FGr K' },
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Chef-", "Einsatzleiter-", "Alpha-", "Kommando-", "Lagezentrum-", "Strategie-", "Master-", "Ober-", "Haupt-", "Krisenstab-", "Taktik-", "Stabs-", "Kontroll-", "Präsidial-", "Generalstabs-"];
                const adjektive = ["Leitender", "Dominanter", "Entscheidender", "Souveräner", "Wichtiger", "Finaler", "Strategischer", "Taktischer", "Autoritärer", "Unumstößlicher", "Befehlender", "Delegierender", "Charismatischer", "Bürokratischer", "Visionärer"];
                const namen = [
                    "Häuptling", "General", "Direktor", "Boss", "Pate", "Meister", "Stratege", "Koordinator", "Platzhirsch", "Alphatier", "Big-Boss", "Kuttenträger", "Präsident", "Imperator", "Kanzler", "Senator",
                    "Admiral", "Befehlshaber", "Vorstand", "CEO", "Aufsichtsrat", "Feldmarschall", "Patriarch", "Magnat", "Strippenzieher", "Dirigent", "Zeremonienmeister", "Caesar", "Napoleon", "Sun Tzu", "König", "Bauer",
                    "Läufer", "Springer", "Turm", "Dame", "Rochade", "Gambit", "Masterplan", "Direktive", "Lagekarte", "Führungsstab", "Kommando-Brücke", "Machtwort", "Veto", "Organigramm", "Mastermind-Mobil", "Schachzug",
                    "Exekutivebene", "Eskalationsstufe", "SWOT-Analyse", "Debriefing", "Befehlskette", "Meldekopf", "Task-Force", "Synergy", "Paradigm Shift", "Low-Hanging Fruit", "Game Changer", "Think Tank",
                    "Kaffee-Beauftragter", "Plan-Macher", "Entscheider", "Taktikfuchs", "Kaffee-Stratege", "Meeting-Meister", "Presse-Sprecher", "Westentaschen-General", "Excel-Tabellen-Fürst",
                    "PowerPoint-Pirat", "Dienstwagen-Don", "Bullshit-Bingo-Bus", "Wichtigtuer-Wagen", "Krisen-Kaffee-Kurier", "Zuständigkeits-Zirkus", "Synergie-Shuttle", "Stakeholder-Mobil", "Wichtiger-Willi",
                    "Zuständigkeits-Verschieber", "Meeting-Marathon-Mobil", "PowerPoint-Prinz", "Koryphäe", "Eminenz", "Entscheidungs-Delegierer", "Meeting-Einberufer", "Kaffee-ist-keine-Strategie"
                ];
                const patterns = [() => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}`];
                return patterns.random()();
            }
        },
        luftrettung: {
            name: "Luftrettung", emoji: "🚁",
            targetVehicleTypes: { 31: 'RTH', 61: 'Polizeihubschrauber', 156: 'Polizeihubschrauber mit Winde', 157: 'RTH Winde', 161: 'Hubschrauber (Seenotrettung)' },
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Himmels-", "Luft-", "Wolken-", "Rotor-", "Turbinen-", "Götter-", "Engels-", "Sturm-", "Alpen-", "Aero-", "Gipfel-", "Senkrecht-"];
                const adjektive = ["Fliegender", "Schwebender", "Schneller", "Göttlicher", "Himmlischer", "Stählerner", "Allsehender", "Donnernder", "Windiger", "Kreisender", "Steigender", "Majestätischer"];
                const namen = [
                    "Adler", "Falke", "Bussard", "Kondor", "Greif", "Albatros", "Ikarus", "Pegasus", "Valkyrie", "Garuda", "Erzengel", "Schutzengel", "Himmelsbote", "Retter", "Horus", "Hermes", "Gerfalke",
                    "Milan", "Sturmvogel", "Roch", "Zeus", "Thor", "Simurgh", "Ziz", "Auge", "Winde", "Klinge", "Wirbelsturm", "Himmels-Auge", "Rotorblatt", "Thermik", "Gipfelstürmer", "Senkrechtstarter",
                    "Aufwind", "Föhn", "Jetstream", "Cumulonimbus", "Pilot", "Windenoperator", "Bell UH-1D", "Eurocopter", "Bo 105", "Airbus H145", "Black Hawk", "Apache", "Chinook",
                    "Luft-Taxi", "Propeller-Prinz", "Knatter-Kiste", "Himmels-Fahrstuhl", "Thermik-Tester", "Ventilator-Deluxe", "Teuerstes-Taxi", "Libellen-Lord", "Hummel-Heli", "Brötchen-Holer", "Höhen-Rausch",
                    "Kerosin-Vernichter", "Höhen-Luft-Schnapper", "Adler-Attrappe", "Rotierende-Rettung", "Lawinen-Gucker", "Stau-Uinflieger", "Dach-Landeplatz-Sucher", "Vogel-Schreck", "Wind-Macher"
                ];
                const patterns = [() => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}`];
                return patterns.random()();
            }
        },
        wasserrettung: {
            name: "Wasserrettung", emoji: "🚤",
            targetVehicleTypes: { 63: 'GW-Taucher', 64: 'GW-Wasserrettung', 70: 'MZB' },
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Fluss-", "See-", "Tauch-", "Wasser-", "Wellen-", "Strömungs-", "Ufer-", "Sonar-", "Tiefen-", "Schlick-", "Neopren-"];
                const adjektive = ["Nasser", "Tiefer", "Blubbernder", "Kalter", "Schneller", "Leckgeschlagener", "Schwimmender", "Tauchender", "Feuchter", "Klammer", "Glitschiger"];
                const namen = [
                    "Froschmann", "Kapitän", "Pirat", "Matrose", "Taucher", "Retter", "Wasserratte", "Fluss-Sheriff", "Bademeister", "Otter", "Biber", "Hecht", "Zander", "Wassermann", "Nixe", "Wels", "Kormoran",
                    "Anker", "Schraube", "Sonar", "Rettungsring", "Schlauchboot", "Tauchglocke", "Periskop", "Tiefenmesser", "Schleuse", "Kielwasser", "Strömung", "Neoprenanzug", "Druckluftflasche",
                    "Tauchcomputer", "Trockenanzug", "Hebesack", "Sprungschicht", "Dekompression", "Rhein", "Donau", "Elbe", "Bodensee", "Müritz", "Chiemsee",
                    "Quietsche-Ente", "Bade-Ente", "Gummiboot", "Seepferdchen", "Feuchter-Traum", "Planschbecken-Patrouille", "Unterwasser-Staubsauger", "Schlick-Schlitten", "Blubber-Blitz",
                    "Abtaucher", "Nasser-Willy", "Amphibien-Ambulanz", "Wellen-Reiter", "Fisch-Schreck", "Algen-Mäher", "Schilf-Schneider", "Ente-Nass", "Badewannen-Admiral", "Schlamm-Wühler", "Anker-Auswerfer",
                    "Forelle", "Karpfen", "Aal", "Barsch", "Plötze", "Brachse", "Rotfeder", "Ukelei", "Gründling"
                ];
                const patterns = [() => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}`];
                return patterns.random()();
            }
        },
        seenotrettung: {
            name: "Seenotrettung", emoji: "🚢",
            targetVehicleTypes: { 159: 'Seenotrettungskreuzer', 160: 'Seenotrettungsboot' },
            nameGenerator: function(isLarge = false) {
                const praefixe = ["Küsten-", "Hochsee-", "Sturm-", "Wellen-", "See-", "Meeres-", "Orkan-", "Hafen-", "Tiden-", "Brandungs-", "Salzwasser-", "Gischt-"];
                const adjektive = ["Salziger", "Stürmischer", "Unsinkbarer", "Verwegener", "Rostiger", "Heldenhafter", "Wellenbrechender", "Seetüchtiger", "Tapferer", "Standhafter"];
                const namen = [
                    "Seebär", "Kapitän", "Pirat", "Freibeuter", "Klabautermann", "Neptun", "Poseidon", "Hafenmeister", "Leuchtturmwärter", "Triton", "Ägir", "Ran", "Störtebeker", "Nautilus", "Kolumbus", "Magellan", "Vasco da Gama",
                    "Kraken", "Leviathan", "Moby Dick", "Fliegender Holländer", "Charybdis", "Hydra", "Scylla", "Jörmungandr", "Sextant", "Kompass", "Brandung", "Gischt", "Tide", "Welle", "Düne", "Boje", "Fender", "Poller", "Kiel",
                    "Takelage", "Sturmflut", "Orkanböe", "Kreuzsee", "Titanic", "Bismarck", "Calypso", "Santa Maria", "Mayflower", "Discovery", "Endeavour", "Victoria", "Gorck Fock", "Passat", "Pamir", "Peking",
                    "Rost-Ritter", "Salzwasser-Sänfte", "Wellen-Bezwinger", "Möwen-Schreck", "Fischkutter-Freund", "Eiserner-Wal", "Nasser-Held", "Hafen-Hirte", "Deich-Defender", "Salzwasser-Seelsorger",
                    "Krabben-Kumpel", "Container-Cop", "Treibgut-Taxi", "Wellen-Wiege", "Orkan-Organisator", "Sturm-Stratege", "Rostlauben-Retter", "Möwen-Motel", "Nebel-Navigator", "Kompass-Korrektor", "Albatros", "Kormoran"
                ];
                const patterns = [() => namen.random(), () => `${adjektive.random()} ${namen.random()}`, () => `${praefixe.random()}${namen.random()}`];
                return patterns.random()();
            }
        },
    };

    // ========================================================================
    // 3. KERNFUNKTIONEN
    // ========================================================================
    let vehicleTypeToModuleMap = {};
    function formatTime(seconds) { if (isNaN(seconds) || seconds < 0) return "--:--"; seconds = Math.floor(seconds); const hours = Math.floor(seconds / 3600); const minutes = Math.floor((seconds % 3600) / 60); const remainingSeconds = seconds % 60; if (hours > 0) { return `${hours.toString().padStart(2, '0')}:${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; } else { return `${minutes.toString().padStart(2, '0')}:${remainingSeconds.toString().padStart(2, '0')}`; } }
    async function showBlockControlPanel() { showModal({ title: 'Kontrollzentrum', body: 'Lade Fahrzeug- und Gebäudedaten...' }); try { const [vehicleResponse, buildingResponse] = await Promise.all([gmFetch('/api/vehicles'), gmFetch('/api/buildings')]); if (!vehicleResponse.ok || !buildingResponse.ok) throw new Error('API-Fehler!'); const allVehicles = await vehicleResponse.text().then(JSON.parse); const allBuildings = await buildingResponse.text().then(JSON.parse); const buildingCache = Object.fromEntries(allBuildings.map(b => [b.id, b.caption])); vehicleTypeToModuleMap = {}; for (const moduleKey in MODULE_CONFIG) { for (const typeId in MODULE_CONFIG[moduleKey].targetVehicleTypes) { vehicleTypeToModuleMap[typeId] = moduleKey; } } const bodyElement = document.createElement('div'); const selectAllLine = document.createElement('div'); selectAllLine.className = 'ng-checkbox-line'; selectAllLine.id = 'ng-select-all-line'; selectAllLine.innerHTML = `<label for="check_all"><input type="checkbox" id="check_all"><strong>Alle Blöcke auswählen / abwählen</strong></label>`; bodyElement.appendChild(selectAllLine); for (const moduleKey in MODULE_CONFIG) { const config = MODULE_CONFIG[moduleKey]; const allTypeIdsInModule = Object.keys(config.targetVehicleTypes); const vehiclesInModule = allVehicles.filter(v => allTypeIdsInModule.some(id => id == v.vehicle_type)); const count = vehiclesInModule.length; if (count === 0) continue; const needed = vehiclesInModule.filter(v => !v.caption.endsWith(MARKER)).length; const line = document.createElement('div'); line.className = 'ng-checkbox-line'; line.innerHTML = `<label for="check_${moduleKey}"><input type="checkbox" id="check_${moduleKey}" data-modulekey="${moduleKey}"> ${config.emoji} ${config.name} <span class="count">(Gesamt: ${count} / Nötig: ${needed})</span></label>`; bodyElement.appendChild(line); } bodyElement.querySelector('#check_all').addEventListener('change', (e) => { const isChecked = e.target.checked; bodyElement.querySelectorAll('input[data-modulekey]').forEach(cb => cb.checked = isChecked); }); const actions = [ { label: 'Loslegen (Nötige umbenennen)', className: 'btn-start', callback: () => { const selectedModules = Array.from(bodyElement.querySelectorAll('input[data-modulekey]:checked')).map(cb => cb.dataset.modulekey); if (selectedModules.length === 0) { alert("Bitte wähle mindestens einen Block aus."); return; } let allSelectedTypeIds = []; selectedModules.forEach(key => allSelectedTypeIds.push(...Object.keys(MODULE_CONFIG[key].targetVehicleTypes))); const vehiclesToProcess = allVehicles.filter(v => allSelectedTypeIds.some(id => id == v.vehicle_type) && !v.caption.endsWith(MARKER)); if (vehiclesToProcess.length > 0) startRenamingProcess(vehiclesToProcess, buildingCache); else alert("Keine Fahrzeuge für diese Auswahl zur Umbenennung nötig."); } }, { label: 'Alles überschreiben (erzwingen)', className: 'btn-warning', callback: () => { const selectedModules = Array.from(bodyElement.querySelectorAll('input[data-modulekey]:checked')).map(cb => cb.dataset.modulekey); if (selectedModules.length === 0) { alert("Bitte wähle mindestens einen Block aus."); return; } let allSelectedTypeIds = []; selectedModules.forEach(key => allSelectedTypeIds.push(...Object.keys(MODULE_CONFIG[key].targetVehicleTypes))); const vehiclesToProcess = allVehicles.filter(v => allSelectedTypeIds.some(id => id == v.vehicle_type)); if (vehiclesToProcess.length > 0 && confirm(`ACHTUNG!\n\Möchtest du wirklich ALLE ${vehiclesToProcess.length} Fahrzeuge der ausgewählten Blöcke neu benennen?`)) { startRenamingProcess(vehiclesToProcess, buildingCache); } } }, { label: 'Schließen', className: 'btn-close', callback: () => document.body.removeChild(document.getElementById('ng-modal-overlay')) }]; showModal({ title: 'Namensgenerator Kontrollzentrum', bodyElement: bodyElement, actions: actions }); } catch (error) { showModal({ title: 'Fehler', body: `Ein Fehler ist aufgetreten:\n${error.message}` }); } }
    async function startRenamingProcess(vehicles, buildingCache) { const startTime = Date.now(); showModal({ title: `Benennung läuft...`, body: '', progress: true, actions: [{ label:'Abbrechen', className:'btn-close', callback:()=> { vehicles.length = 0; document.body.removeChild(document.getElementById('ng-modal-overlay')); } }] }); const progressBar = document.getElementById('ng-progress-bar'); const progressText = document.getElementById('ng-progress-text'); const logArea = document.getElementById('ng-log-area'); logArea.value = 'Initialisiere...\n'; try { const firstVehicleId = vehicles[0]?.id; if (!firstVehicleId) { throw new Error("Konnte keine gültige Fahrzeug-ID für den Token-Abruf finden."); } const authToken = await gmFetch(`/vehicles/${firstVehicleId}/edit`).then(r => r.text()).then(html => new DOMParser().parseFromString(html, "text/html").querySelector('meta[name="csrf-token"]').getAttribute('content')); logArea.value += 'Sicherheitstoken erfolgreich erhalten. Starte Batch-Verarbeitung...\n'; const usedNames = new Set(); const jobList = vehicles.map(v => { const moduleKey = vehicleTypeToModuleMap[v.vehicle_type]; if (!moduleKey) return null; const config = MODULE_CONFIG[moduleKey]; let spitzname; let attempts = 0; do { spitzname = config.nameGenerator(config.largeVehicleIds && config.largeVehicleIds.includes(v.vehicle_type)); attempts++; } while (usedNames.has(spitzname) && attempts < 20); usedNames.add(spitzname); const stationName = buildingCache[v.building_id] || "Unbekannte Wache"; const vehicleType = config.targetVehicleTypes[v.vehicle_type]; const newCaption = `${vehicleType} ${spitzname} [${stationName}]${MARKER}`; return { id: v.id, newCaption: newCaption, oldCaption: v.caption }; }).filter(Boolean); let processedCount = 0; let successCount = 0; let errorCount = 0; const performanceLog = []; for (let i = 0; i < jobList.length; i += BATCH_SIZE) { if (vehicles.length === 0) { logArea.value += `\n\nProzess vom Benutzer abgebrochen.`; break; } const batch = jobList.slice(i, i + BATCH_SIZE); logArea.value += `\nVerarbeite Paket ${Math.ceil((i + 1) / BATCH_SIZE)} / ${Math.ceil(jobList.length / BATCH_SIZE)}...\n`; await Promise.allSettled(batch.map(job => { const formData = new URLSearchParams(); formData.append('utf8', '✓'); formData.append('_method', 'patch'); formData.append('authenticity_token', authToken); formData.append('vehicle[caption]', job.newCaption); return gmFetch(`/vehicles/${job.id}`, { method: 'POST', headers: { 'Content-Type': 'application/x-www-form-urlencoded' }, body: formData.toString() }).then(response => { if (response.ok) { successCount++; } else { errorCount++; } logArea.value += `${response.ok ? 'OK' : 'FEHLER'}: "${job.oldCaption}" -> "${job.newCaption.slice(0,-1)}"\n`; }).catch(e => { errorCount++; logArea.value += `FEHLER bei "${job.oldCaption}": ${e.message}\n`; }).finally(() => { logArea.scrollTop = logArea.scrollHeight; }); })); processedCount += batch.length; performanceLog.push({ time: Date.now(), count: processedCount }); if (performanceLog.length > 5) { performanceLog.shift(); } let etaString = '--:--'; if (performanceLog.length > 1) { const first = performanceLog[0]; const last = performanceLog[performanceLog.length - 1]; const processedInWindow = last.count - first.count; const timeInWindow = last.time - first.time; if (timeInWindow > 100) { const itemsPerSecond = processedInWindow / (timeInWindow / 1000); const remainingItems = jobList.length - processedCount; if (itemsPerSecond > 0) { const remainingTimeInSeconds = remainingItems / itemsPerSecond; etaString = formatTime(remainingTimeInSeconds); } } } const progress = (processedCount / jobList.length) * 100; progressBar.style.width = `${progress}%`; progressText.textContent = `${processedCount} / ${jobList.length} | ETA: ${etaString}`; } const totalTime = formatTime((Date.now() - startTime) / 1000); progressBar.style.backgroundColor = '#28a745'; progressText.textContent = `Verarbeitung abgeschlossen!`; logArea.value += `\nProzess beendet nach ${totalTime}. Erfolgreich: ${successCount}, Fehler: ${errorCount}.\n`; logArea.scrollTop = logArea.scrollHeight; } catch (error) { logArea.value += `\nEin schwerwiegender Fehler ist aufgetreten: ${error.message}\nProzess abgebrochen.`; if (document.getElementById('ng-progress-bar')) document.getElementById('ng-progress-bar').style.backgroundColor = '#dc3545'; } }
    function showModal(config){const oldOverlay=document.getElementById('ng-modal-overlay');if(oldOverlay)document.body.removeChild(oldOverlay);const overlay=document.createElement('div');overlay.id='ng-modal-overlay';const modalContent=document.createElement('div');modalContent.id='ng-modal-content';modalContent.innerHTML=`<h3>${config.title}</h3>`;const modalBody=document.createElement('div');modalBody.id='ng-modal-body';if(config.bodyElement){modalBody.appendChild(config.bodyElement)}else if(config.body){modalBody.innerHTML=config.body}modalContent.appendChild(modalBody);if(config.progress){const progressArea=document.createElement('div');progressArea.innerHTML=`<div id="ng-progress-bar-container"><div id="ng-progress-bar"></div></div><div id="ng-progress-text">Initialisiere...</div><textarea id="ng-log-area" readonly></textarea>`;modalContent.appendChild(progressArea)}const buttonContainer=document.createElement('div');buttonContainer.id='ng-modal-buttons';if(config.actions){config.actions.forEach(action=>{const button=document.createElement('button');button.className=`ng-modal-btn ${action.className||''}`;button.textContent=action.label;button.addEventListener('click',action.callback);buttonContainer.appendChild(button)})}modalContent.appendChild(buttonContainer);overlay.appendChild(modalContent);document.body.appendChild(overlay);return{overlay,modalContent}}
    function gmFetch(url,options={}){return new Promise((resolve,reject)=>{GM_xmlhttpRequest({method:options.method||'GET',url:`https://www.leitstellenspiel.de${url}`,headers:options.headers||{},data:options.body,timeout:15000,onload:(response)=>{if(response.status>=200&&response.status<300){response.ok=true;response.text=()=>Promise.resolve(response.responseText);resolve(response)}else{reject(new Error(`Server-Fehler: Status ${response.status}`))}},onerror:(error)=>reject(new Error('Netzwerk- oder Skript-Konflikt-Fehler.')),ontimeout:()=>reject(new Error('Zeitüberschreitung der Anfrage.'))})})}
    const addGeneratorButton=()=>{const settingsLink=document.querySelector('a.lightbox-open[href="/settings/index"]');if(!settingsLink)return;const settingsListItem=settingsLink.closest('li');if(!settingsListItem)return;const mainMenu=settingsListItem.parentElement;if(!mainMenu||document.getElementById('main-naming-button')){if(mainMenu){observer.disconnect()}return}const newListItem=document.createElement('li');newListItem.setAttribute('role','presentation');const mainButton=document.createElement('a');mainButton.href="#";mainButton.id='main-naming-button';mainButton.innerHTML=`<span style="font-size: 20px; vertical-align: -3px; margin-right: 5px; display: inline-block;">🏷️</span> Fahrzeug-Namen-Generator`;mainButton.style.cursor="pointer";mainButton.addEventListener('click',(e)=>{e.preventDefault();showBlockControlPanel()});settingsListItem.insertAdjacentElement('afterend',newListItem);newListItem.appendChild(mainButton);observer.disconnect()};
    const observer = new MutationObserver(addGeneratorButton);
    observer.observe(document.body, { childList: true, subtree: true });
    addGeneratorButton();

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址