diff --git a/src/structure/components/com_sportsmanager/admin.php b/src/structure/components/com_sportsmanager/admin.php index 8d97514..9047b26 100644 --- a/src/structure/components/com_sportsmanager/admin.php +++ b/src/structure/components/com_sportsmanager/admin.php @@ -4620,11 +4620,7 @@ function adminEditTeamspielmodus(): void if ($punkte_vorsprung_doppel > 1 && $punkte_sieg_doppel < 0) $punkte_sieg_doppel = abs($punkte_sieg_doppel); // Ohne Siegbedingung („Beliebig") gibt es nichts, worauf sich Vorsprung oder Deckelung - // beziehen koennten. Dann bleiben beide auf ihren neutralen Werten, statt eine Regel zu - // behaupten, die nirgends greift. - // Ohne geforderten Vorsprung endet ein Spiel EXAKT beim Siegwert — dann kann eine - // Grenze nie greifen, und sie zu speichern hiesse, eine Regel zu behaupten, die nichts - // tut (Sven 2026-09-01). Gilt auf jeder Ebene gleich. + // beziehen koennten. if ($punkte_vorsprung_einzel <= 1) $punkte_deckel_einzel = 0; if ($punkte_vorsprung_doppel <= 1) $punkte_deckel_doppel = 0; if ($punkte_sieg_einzel == 0) { @@ -4707,20 +4703,10 @@ function adminEditTeamspielmodus(): void $saetze_modus_einzel = 0; $saetze_modus_doppel = 0; } - // Die Satzzahl wird ZUSAETZLICH nach punkte_sieg_* gespiegelt — dorthin, wo seit jeher - // steht, bei wievielen Saetzen ein Spiel gewonnen ist. Eine aeltere Programmfassung - // liest damit weiter dieselbe wahre Aussage, obwohl sie die neue Spalte nicht kennt. - // - // Gewinnsaetze sind diese Aussage unmittelbar: N Gewinnsaetze = „gewonnen bei N". - // Aber auch eine feste Satzzahl laesst sich vollstaendig so sagen, denn sie legt fest, - // welche Endstaende es gibt: bei 4 festen Saetzen sind 4:0, 3:1 und 2:2 moeglich, also - // „gewonnen bei 3, Unentschieden bei 2:2" — genau die Bedeutung des negativen - // Vorzeichens. Bei ungerader Satzzahl gibt es kein Unentschieden: 3 feste Saetze heissen - // „gewonnen bei 2". Das ist die Umkehrung der Ueberfuehrung (Datenbankversion 124) und - // deshalb verlustfrei in beide Richtungen. - // - // Fuer punkte_sieg_* = 0 („keine Siegbedingung") bleibt damit nur, was es auch bisher - // meinte: „Beliebig" — keine Angabe zur Satzzahl. + // Die Satzzahl wird ZUSAETZLICH nach punkte_sieg_* gespiegelt, damit eine aeltere + // Programmfassung dieselbe wahre Aussage liest: N Gewinnsaetze als N, eine feste + // Satzzahl als den Stand, bei dem sie entschieden ist. Umkehrung der Ueberfuehrung + // in update.php, also verlustfrei. $sieg_aus_satzzahl = function ($modus) { if ($modus < 0) return -$modus; // N Gewinnsaetze if ($modus == 0) return null; // keine Angabe @@ -4826,12 +4812,9 @@ function adminEditTeamspielmodus(): void if (strlen($verknuepfungen) > 0) $modus .= "|" . $verknuepfungen; - // Erst hier, weil das Ziel die Anzahl der Spiele braucht: Race setzt „ein Satz je - // Spiel" und „Spielergebnis als Spielpunkte" voraus, und das Ziel wird in die - // Altfelder gespiegelt — dieselbe wahre Aussage, die dort seit jeher steht („das Spiel - // ist bei N Toren gewonnen"), damit eine aeltere Programmfassung nichts Falsches liest. - // Vorsprung und Grenze werden NICHT gespiegelt: sie gelten nur fuer das letzte Spiel, - // waehrend die Altfelder fuer alle gelten wuerden. + // Erst hier, weil das Ziel die Anzahl der Spiele braucht: Race setzt „ein Satz je Spiel" + // und „Spielergebnis als Spielpunkte" voraus, und das Ziel wird in die Altfelder gespiegelt + // — dieselbe wahre Aussage, die dort seit jeher steht („das Spiel ist bei N Toren if ($zaehlweise == 1) { $spiele_anzahl = count(array_filter(explode(",", explode("|", $modus)[0]), 'strlen')); $race_ziel = $spiele_anzahl * $race_schritt; @@ -11217,13 +11200,8 @@ function adminSaveBegegnungSpielplan(): void } else { $spiel_heim_punkte_detailliert = $begegnung_input->get('spiel_' . $spiel_nr . '_heim_punkte_detailliert', array(), 'ARRAY'); $spiel_gast_punkte_detailliert = $begegnung_input->get('spiel_' . $spiel_nr . '_gast_punkte_detailliert', array(), 'ARRAY'); - // Ein Formular mit Satzfeldern schickt sie fuer JEDES Spiel mit, auch fuer die, - // in denen nichts steht. Durchweg leere Satzfelder sind aber keine Aussage ueber - // Saetze — sie sagen „hier wurde nichts eingetragen". Ohne diese Unterscheidung - // gewinnt die leere Satzangabe gegen ein vorhandenes Summenergebnis, und das - // blosse Oeffnen und Speichern einer alten Begegnung loescht sie: gemessen an - // einer Begegnung mit sieben gespeicherten Spielen, von denen nach dem Speichern - // eines uebrig war. + // Durchweg leere Satzfelder sind keine Aussage ueber Saetze, sondern „hier wurde + // nichts eingetragen" — sonst loescht blosses Oeffnen und Speichern den Altbestand. $satzfelder_leer = true; foreach ($spiel_heim_punkte_detailliert as $wert) { if ($wert !== '' && $wert !== null) { @@ -11246,18 +11224,9 @@ function adminSaveBegegnungSpielplan(): void if (empty($spiel_heim_punkte_detailliert)) { $spiel_heim_punkte = $begegnung_input->get('spiel_' . $spiel_nr . '_heim_punkte', 0, 'INT'); $spiel_gast_punkte = $begegnung_input->get('spiel_' . $spiel_nr . '_gast_punkte', 0, 'INT'); - // Der gespiegelte Stand („3:1") steht seit jeher in ergebnis_detailliert, - // wenn eine Meldung ohne Satzfelder kommt. Wo der Wettbewerb Ergebnisse JE - // SATZ fuehrt, ist dieses eine Paar aber irrefuehrend: das Feld bedeutet - // dort Saetze, und wer es so liest, sieht einen Satz mit drei Toren und - // rechnet daraus 1:0 statt 3:1 (genau der Fehler, der in unserer eigenen - // App steckte). Ein Altclient, der die Einstellung nicht kennt, meldet - // genau so — deshalb bleibt das Feld dann LEER: der Satzstand steht in - // teamspiel_*_punkte, und die Tore darin sind eben nicht bekannt. - // - // Erfundene Platzhalter („1:0" je gewonnenen Satz) waeren die Alternative - // und sind bewusst verworfen: gespeichert liesse sie niemand mehr von einer - // echten Meldung unterscheiden (Sven 2026-09-03). + // Wo der Wettbewerb Ergebnisse JE SATZ fuehrt, bleibt ergebnis_detailliert bei einer + // Meldung ohne Satzfelder LEER: das eine Paar bedeutet dort Saetze, und wer es als + // Tore liest, rechnet 1:0 statt 3:1. Der Satzstand steht in teamspiel_*_punkte. $ergebnis_detailliert = ($spiel_heim_punkte == 0 && $spiel_gast_punkte == 0) || !empty($teamspiel_modus->satzergebnisse) ? '' @@ -11317,15 +11286,8 @@ function adminSaveBegegnungSpielplan(): void $spiel_gast_spieler_2_id = $t; } - // Echte Satzergebnisse nicht durch ihren eigenen Spiegel ersetzen. - // - // Stellt jemand einen Wettbewerb von „Mehrere - mit Ergebnis je Satz" zurueck - // auf „nur der Satzstand", bietet das Formular danach nur noch die - // Summenfelder — und ein blosses Oeffnen und Speichern schriebe „3:1" ueber - // ein gespeichertes „6:3 3:6 6:3". Eng gefasst: nur wenn dieser Aufruf gar - // keine Satzfelder mitbringt, der Stand unveraendert bleibt und im Bestand - // mehr als ein Paar steht, bleibt der Detailtext, wie er ist (Sven - // 2026-09-01). + // Echte Satzergebnisse nicht durch ihren eigenen Spiegel ersetzen: bringt ein Aufruf + // keine Satzfelder mit und stehen im Bestand mehrere Paare, bleibt der Detailtext. if (isset($spiel_heim_punkte_detailliert) && empty($spiel_heim_punkte_detailliert) && isset($spiele_nummern[$spiel_nr])) { $bestand = $spiele_nummern[$spiel_nr]; @@ -11363,6 +11325,16 @@ function adminSaveBegegnungSpielplan(): void $total_heim_punkte += $spiel_heim_punkte; $total_gast_punkte += $spiel_gast_punkte; + // Gleichstand ist nicht immer ein Unentschieden. Wo eine Zahl von GEWINNSAETZEN + // gilt, hat ein Spiel mit gleichem Satzstand einfach noch keinen Sieger — es ist + // unfertig, und dafuer gibt es keinen Punkt. Ohne Angabe zur Satzzahl bleibt es + // beim bisherigen Verhalten. + $remis_moeglich = function ($saetze_modus) { + if ($saetze_modus == 0) return true; // keine Angabe + if ($saetze_modus < 0) return false; // Gewinnsaetze: am Ende steht keiner gleich + return $saetze_modus % 2 == 0; // feste Satzzahl: nur eine gerade endet remis + }; + if ($spieltyp[0] != "D") { if ($spielpunkte_wertung_einzel == 2) { $spiel_heim_spielpunkte = $spiel_heim_punkte; @@ -11377,7 +11349,8 @@ function adminSaveBegegnungSpielplan(): void } else if ($spiel_heim_punkte == 0 && $spiel_gast_punkte == 0) { $spiel_heim_spielpunkte = 0; $spiel_gast_spielpunkte = 0; - } else if ($spielpunkte_wertung_einzel != 3) { + } else if ($spielpunkte_wertung_einzel != 3 + && $remis_moeglich($teamspiel_modus->saetze_modus_einzel)) { $spiel_heim_spielpunkte = 1; $spiel_gast_spielpunkte = 1; } else { @@ -11399,7 +11372,8 @@ function adminSaveBegegnungSpielplan(): void } else if ($spiel_heim_punkte == 0 && $spiel_gast_punkte == 0) { $spiel_heim_spielpunkte = 0; $spiel_gast_spielpunkte = 0; - } else if ($spielpunkte_wertung_doppel != 3) { + } else if ($spielpunkte_wertung_doppel != 3 + && $remis_moeglich($teamspiel_modus->saetze_modus_doppel)) { $spiel_heim_spielpunkte = 1; $spiel_gast_spielpunkte = 1; } else { diff --git a/src/structure/components/com_sportsmanager/database/update.php b/src/structure/components/com_sportsmanager/database/update.php index 4b0586f..bc142e2 100644 --- a/src/structure/components/com_sportsmanager/database/update.php +++ b/src/structure/components/com_sportsmanager/database/update.php @@ -5789,71 +5789,22 @@ function updateDatabase(): void if ($datenbank_version < 122) { - // SIEGBEDINGUNGEN vollstaendig abbilden (Issue #304). + // Siegbedingungen vollstaendig abbilden (Issue #304). Muss der LETZTE Block der + // Kette bleiben, sonst bleibt die kleinere Versionsnummer stehen. // - // Datenbankversion 122, nicht 121: 121 gehoert dem Hall-of-Fame-Zweig (PR #303, - // Issue #300), der die Spalten teamspieler und nicht_ausgespielt bringt. Dieser - // Block muss der LETZTE der Kette bleiben. Die Reihenfolge ist nicht bloss Kosmetik: - // $datenbank_version wird einmal am Anfang gelesen, also laufen beide Bloecke im - // selben Aufruf — aber jeder schreibt am Ende seine eigene Nummer, und die des - // zuletzt gelaufenen bleibt stehen. Stuende dieser Block vor dem 121er, waere die - // gespeicherte Version danach 121, und beim naechsten Seitenaufruf liefe alles - // erneut. + // Wertebereiche der neuen Spalten: + // satz_sieg_* 0 = nicht hinterlegt; sonst Betrag = Siegwert, negativ + // erlaubt ein Remis ein Tor darunter (wie punkte_sieg_*) + // saetze_modus_* 0 = wie bisher, N > 0 = feste Satzzahl, -N = N Gewinnsaetze + // entscheidung_* 0 = keine Abweichung vom satz_*-Wert + // zaehlweise 0 = je Spiel, 1 = Race (Stand laeuft durch die Begegnung) // - // Bisher sagte ein Mannschaftsspielmodus mit einer einzigen Zahl, wann ein Spiel - // endet: punkte_sieg_einzel/_doppel, deren Vorzeichen zusaetzlich ein - // Unentschieden zulaesst. Verbreitete Modi sind damit nicht darstellbar — „6 Tore, - // aber zwei Vorsprung, spaetestens bei 8" —, und wer nach Saetzen spielt, kann die - // Regel des einzelnen Satzes nirgends hinterlegen. Diese Ueberfuehrung ergaenzt - // deshalb drei Ebenen derselben Regel, die Satzzahl, die Angabe ob Saetze einzeln - // eingetragen werden, und eine Zaehlweise. + // satzergebnisse ist eine EIGENE Spalte und kein dritter punktetyp-Wert: punktetyp + // ist das Feld, aus dem fremde Anwendungen ablesen, ob die Punkte eines Spiels Tore + // oder Saetze sind, und kennt seit jeher zwei Werte. // - // Alle Vorgabewerte beschreiben GENAU das heutige Verhalten, und keine bestehende - // Spalte wird angetastet. Eine aeltere Programmfassung liest die neuen Spalten - // nicht und rechnet unveraendert weiter; ein Client, der nur die ueberlieferten - // Felder kennt, findet dort dieselbe Auskunft wie vorher. - // - // SPIELEBENE — punkte_vorsprung_* (wie viele klar voraus, 1 = ein Tor genuegt, also - // das heutige Verhalten) und punkte_deckel_* (Wert, bei dem das Spiel unabhaengig - // vom Vorsprung endet, 0 = keine Grenze). - // - // SATZEBENE — satz_sieg_* (0 = nicht hinterlegt, also der heutige Zustand; sonst - // dasselbe Vorzeichen wie punkte_sieg_*: Betrag = Siegwert, negativ erlaubt ein - // Remis ein Tor darunter), satz_vorsprung_*, satz_deckel_*. Die Regel INNERHALB - // eines Satzes hatte bisher keinen Platz: punkte_sieg_* misst dort, je nach - // punktetyp, entweder Tore („Einer") oder gewonnene Saetze („Mehrere"). - // - // SATZZAHL — saetze_modus_*: 0 = wie bisher (allein punkte_sieg_* zaehlt Saetze, - // keine feste Zahl, kein Entscheidungssatz), N > 0 = feste Satzzahl N (alle werden - // gespielt), -N = N Gewinnsaetze (hoechstens 2N-1 Saetze, der letzte ist der - // Entscheidungssatz). Der Editor schreibt die Satzzahl ZUSAETZLICH nach - // punkte_sieg_* zurueck, damit eine aeltere Programmfassung dieselbe — wahre — - // Aussage liest wie bisher: N Gewinnsaetze als N, eine feste Satzzahl als den - // Stand, bei dem sie entschieden ist (4 feste Saetze = „gewonnen bei 3, - // Unentschieden bei 2:2" = -3; 3 feste Saetze = „gewonnen bei 2" = 2). Diese - // Spiegelung ist die Umkehrung der Ueberfuehrung unten und damit verlustfrei. - // - // ENTSCHEIDUNGSSATZ — entscheidung_*: abweichende Regel fuer den Satz, der bei N - // Gewinnsaetzen nach N-1 zu N-1 noch aussteht; sonst gilt satz_*. - // entscheidung_sieg_* = 0 heisst „keine Abweichung" und ist der Bestandswert. - // - // SATZERGEBNISSE — satzergebnisse: werden die Saetze eines Spiels mit ihrem - // jeweiligen Ergebnis eingetragen? Eine EIGENE Spalte und ausdruecklich kein - // dritter Wert in punktetyp: punktetyp ist das einzige Feld, aus dem eine fremde - // Anwendung ablesen muss, ob die Punkte eines Spiels Tore oder gewonnene Saetze - // sind, und es kennt seit jeher genau zwei Werte. Ein dritter haette jede Anwendung - // getroffen, die „1 = Saetze, sonst Tore" schreibt statt „0 = Tore, sonst Saetze" — - // beide Fassungen stehen im Sports Manager selbst, und mindestens ein Client - // (Kickern) ist von hier aus nicht mitzuziehen. So behaelt punktetyp seine - // Bedeutung: die Punkte SIND weiter die gewonnenen Saetze, die feinere Erfassung - // aendert daran nichts, und wer die neue Spalte nicht liest, verpasst das - // Zusaetzliche statt Falsches zu behaupten. - // - // ZAEHLWEISE — zaehlweise/race_*: im Race-Modus laeuft der Stand durch die ganze - // Begegnung, Spiel N endet also, wenn eine Seite N mal race_schritt erreicht. - // Eingetragen wird wie bisher die Differenz des einzelnen Spiels. race_vorsprung, - // race_deckel und race_remis gehoeren zum ZIEL, gelten also nur fuer das letzte - // Spiel der Folge. zaehlweise = 0 ist jeder Wettbewerb, der nichts anderes sagt. + // Alle Vorgabewerte beschreiben das heutige Verhalten; keine bestehende Spalte wird + // angetastet. $columns = $db->getTableColumns('#__sportsmanager_teamspiel_modus'); if (!array_key_exists('satzergebnisse', $columns)) { $query = "ALTER TABLE `#__sportsmanager_teamspiel_modus`" @@ -5887,28 +5838,12 @@ function updateDatabase(): void } } - // Bestehende „Mehrere"-Modi in die Satzzahl ueberfuehren. - // - // * punkte_sieg_* = 1 → ein Satz, und der wird gespielt. - // * punkte_sieg_* = N (ab 2) → N GEWINNSAETZE. Von den beiden Lesarten, die diese - // Zahl zulaesst (best of 2N-1 oder feste 2N-1 Saetze), ist das die weitaus - // haeufigere; wessen Wettbewerb alle Saetze ausspielt, stellt eine Auswahl um. - // * punkte_sieg_* = -N → FESTE Satzzahl 2(N-1). Das Vorzeichen bedeutet „Remis bei - // N-1 zu N-1 moeglich", und ein Remis setzt voraus, dass alle Saetze gespielt - // werden: bei „Sieg 3, Remis 2:2" sind es vier. - // * 0 bleibt 0 und heisst „Beliebig": da war nie eine Regel. - // - // Auch ungewoehnliche Zahlen werden ueberfuehrt, nicht liegengelassen (Sven - // 2026-09-02). In „Mehrere" MISST punkte_sieg_* gewonnene Saetze — das ist die - // Bedeutung des Feldes, auch wenn ein Wettbewerb sie fuer Tore benutzt hat. Der - // Editor bietet solche Werte nicht zur Wahl an, zeigt den vorhandenen aber als - // eigenen Eintrag: sichtbar, unveraendert speicherbar, und einmal weggestellt - // nicht mehr einstellbar. - // - // Der Race-Modus wird NICHT automatisch erkannt; er ist aus Bestandsdaten nicht - // sicher abzuleiten und wird einmal von Hand gewaehlt. - // - // Nur dort, wo noch nichts gesetzt ist — ein zweiter Lauf aendert nichts. + // Bestehende „Mehrere"-Modi in die Satzzahl ueberfuehren — die Umkehrung der + // Spiegelung, die der Editor beim Speichern vornimmt: + // punkte_sieg_* 1 -> ein fester Satz + // N -> N Gewinnsaetze (haeufigere der beiden Lesarten) + // -N -> feste Satzzahl 2(N-1) (Remis setzt alle Saetze voraus) + // 0 -> bleibt 0 („Beliebig") $query = "UPDATE #__sportsmanager_teamspiel_modus" . "\n SET saetze_modus_einzel = CASE" . "\n WHEN punktetyp = 0 THEN 0" diff --git a/src/structure/components/com_sportsmanager/views/sportsmanager/view_admin.php b/src/structure/components/com_sportsmanager/views/sportsmanager/view_admin.php index 82a1390..f76d79c 100644 --- a/src/structure/components/com_sportsmanager/views/sportsmanager/view_admin.php +++ b/src/structure/components/com_sportsmanager/views/sportsmanager/view_admin.php @@ -4665,27 +4665,15 @@ class HTML_sportsmanager_admin $entscheidung_moeglich = $saetze_moeglich && ($row->saetze_modus_einzel ?? 0) < 0; $entscheidung_moeglich_doppel = $doppel_separat && !empty($row) && $row->punktetyp != 0 && ($row->saetze_modus_doppel ?? 0) < 0; - // Wer die Satzzahl waehlt, legt damit die Siegbedingung des Spiels fest — Vorsprung - // und Deckelung auf Spielebene haetten daneben nichts mehr zu sagen. - // Bei „Mehrere" beantwortet die Satzzahl die Frage vollstaendig — „Spiel - // abgeschlossen bei" waere eine zweite Antwort auf dieselbe (Sven 2026-09-01). - // Die Auswahl bleibt im Dokument und sendet weiter ihren Wert, wird aber nicht - // mehr angeboten: ein Altwert ueberlebt dadurch unveraendert, ohne dass man ihn - // neu einstellen koennte. + // Wer die Satzzahl waehlt, legt damit die Siegbedingung des Spiels fest — Vorsprung und + // Deckelung auf Spielebene haetten daneben nichts mehr zu sagen. $eigene_spielregel_verborgen = $saetze_moeglich; $eigene_spielregel_verborgen_doppel = $saetze_moeglich; // Im Race-Modus laeuft der Stand ueber die Begegnung durch; die Regeln des // einzelnen Spiels und des Satzes gibt es dort nicht. $race_an = !empty($row) && ($row->zaehlweise ?? 0) != 0; - // Die Einheit der SPIELEBENE haengt an punktetyp: Tore bei „Einer", gewonnene - // Saetze bei „Mehrere". Bisher stand dort in beiden Faellen „Punkte" — und genau - // daran war eine Fehlkonfiguration nicht zu erkennen: „42 Punkte" liest sich - // plausibel, „42 Saetze" haette sofort auffallen lassen, dass hier Tore gemeint - // waren (Sven 2026-09-01). - // - // Beide Beschriftungen entstehen serverseitig und reisen als data-Attribut mit; - // beim Umschalten von punktetyp tauscht zeilen_anzeigen() sie ein. So bleibt jede - // Sprache uebersetzt, statt in JavaScript ein Wort zu raten. + // Die Einheit der Spielebene haengt an punktetyp: Tore bei „Einer", gewonnene + // Saetze bei „Mehrere". Vorher stand in beiden Faellen „Punkte". $einheit_option = function ($wert, $gewaehlt, $tore, $saetze) use ($saetze_moeglich) { return " - @@ -5356,7 +5329,7 @@ class HTML_sportsmanager_admin : - - @@ -5443,7 +5416,7 @@ class HTML_sportsmanager_admin : - @@ -5495,7 +5468,7 @@ class HTML_sportsmanager_admin : - - @@ -5574,7 +5547,7 @@ class HTML_sportsmanager_admin : - @@ -5624,7 +5597,7 @@ class HTML_sportsmanager_admin : - - @@ -5703,7 +5676,7 @@ class HTML_sportsmanager_admin : - Text::_('COM_SPORTSMANAGER_OPTIONAL'), 1 => Text::_('COM_SPORTSMANAGER_OPTIONAL_BUT_SAME_IN_DOUBLES'), 2 => Text::_('COM_SPORTSMANAGER_REQUIRED')); @@ -5745,7 +5718,7 @@ class HTML_sportsmanager_admin : - @@ -5818,7 +5786,7 @@ class HTML_sportsmanager_admin - @@ -5887,7 +5855,7 @@ class HTML_sportsmanager_admin @@ -12776,13 +12738,9 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void $punkte_vorsprung_doppel = max(1, (int)($teamspiel_modus->punkte_vorsprung_doppel ?? 1)); $punkte_deckel_einzel = max(0, (int)($teamspiel_modus->punkte_deckel_einzel ?? 0)); $punkte_deckel_doppel = max(0, (int)($teamspiel_modus->punkte_deckel_doppel ?? 0)); - // Zweite Ebene: die Regel im einzelnen Satz. Eingetragen werden einzelne Saetze - // nur bei „Mehrere mit Satzergebnissen" — nur dort greift sie also. - // Eine Mannschaft ohne hinterlegte Spieler braucht keine Spielerauswahl: - // das Feld haette nur den Leereintrag und behauptete eine Wahl, die es nicht - // gibt (Sven 2026-09-02). Gespeichert wird dann genau wie bei einer leeren - // Auswahl — der Server liest die fehlenden Felder mit Vorgabe 0, also - // „kein Spieler", und `$spieler_angegeben` bleibt falsch. + // Zweite Ebene: die Regel im einzelnen Satz. Eingetragen + // werden einzelne Saetze nur bei „Mehrere mit + // Satzergebnissen" — nur dort greift sie also. $heim_hat_spieler = !empty($heim_spieler); $gast_hat_spieler = !empty($gast_spieler); $satzweise = ($teamspiel_modus->satzergebnisse ?? 0) != 0; @@ -12822,24 +12780,8 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void // punkte_gegner brauchen beide Ebenen — das Spiel und der Satz. if ($handheld != "yes" && ($race_an || $punkte_sieg_einzel != 0 || $punkte_sieg_doppel != 0 || ($satzweise && ($satz_sieg_einzel != 0 || $satz_sieg_doppel != 0)))) { - // Der Gegenwert zu einem eingegebenen Stand — also die Ergaenzung, die das - // Formular anbietet, wenn nur eine Seite eingetragen ist. - // - // Ergaenzt wird nur, was eindeutig ist: ein Stand UNTERHALB der Siegbedingung - // kann nicht der des Siegers sein, die andere Seite muss also gewonnen haben. - // Was dazu gehoert, ist `sieg`, bei Vorsprung entsprechend mehr, und nie mehr - // als die Deckelung — Beispiel Sieg 6, Vorsprung 2, Deckel 8: zu 5 gehoert 7, - // zu 4 die 6. - // - // Ein Stand, der selbst gewinnen KOENNTE, wird nicht ergaenzt: zu einer 6 bei - // Sieg 6 gehoert entweder 0..4 (dann hat sie gewonnen) oder 8 (dann verloren) — - // das ist geraten, nicht gefolgert. Leerer Rueckgabewert heisst „nichts - // eintragen"; die bisherige Fassung hatte dafuer eine eigene Abbruchbedingung - // auf Gleichheit mit der Siegbedingung. - // - // Das Unentschieden gilt nur OHNE Vorsprung: bei zwei Toren Vorsprung ist ein - // 5:5 bei „Sieg 6, Remis 5" kein Endstand, sondern ein laufendes Spiel. Der - // Editor speichert diese Kombination deshalb gar nicht mehr. + // Der Gegenwert zu einem eingegebenen Stand: was die andere Seite hoechstens haben + // kann, wenn dieser Stand das Spiel beendet. echo "function punkte_gegner(eingabe, sieg, vorsprung, deckel, unentschieden) {\n" . " var v = Number(eingabe);\n" . " if (unentschieden != 0 && v == unentschieden)\n" @@ -12930,16 +12872,8 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void . "}\n"; } } - // Der Gesamtstand — und zwar DIE Zahl, die die Begegnung nach aussen - // hat: die Spielpunkte. Liste, Mannschaftsseite und die Kopfzeile der - // Begegnungsdetails zeigen alle heim_spielpunkte:gast_spielpunkte, also - // zeigt das Formular sie auch. Ich hatte hier zuerst die Summe der Tore - // gross und die Spielpunkte in Klammern — bei einem 5er-Spielplan stand da - // „6:4 (Spielpunkte 1:0)", wo die Begegnung 1:0 heisst (Sven 2026-09-02). - // - // Gerechnet wie der Server rechnet (admin.php, - // adminSaveBegegnungSpielplan): je Spiel aus der Wertung — Sieg 1/2/3, - // Unentschieden, oder das Ergebnis selbst. + // Der Gesamtstand: die Spielpunkte, wie sie Liste, Mannschaftsseite und Kopfzeile + // zeigen — gerechnet mit derselben Arithmetik wie beim Speichern. echo "function gesamtstand_aktualisieren() {\n" . " var sh = 0, sg = 0, h, g;\n"; for ($i = 1; $i <= count($spieltypen); $i++) { @@ -12994,14 +12928,9 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void . " satzzeilen_anzeigen(nr);\n" . " gesamtstand_aktualisieren();\n" . "}\n" - // Gestaffelt zeigen: sichtbar ist die Mindestzahl, und dahinter genau - // eine leere Zeile — nicht die volle Hoechstzahl. Sonst stuenden bei - // sieben Spielen zu fuenf Saetzen siebzig Auswahlfelder da, von denen - // die meisten leer bleiben. - // - // Alle Zeilen bleiben im Dokument und werden mitgesendet; leere - // Satzpaare ueberspringt der Server ohnehin. Verborgen wird also nur, - // was man sieht, nicht was gespeichert wird. + // Gestaffelt zeigen: sichtbar ist die Mindestzahl, + // und dahinter genau eine leere Zeile — nicht die + // volle Hoechstzahl. . "function satzzeilen_anzeigen(nr) {\n" . " var min = satz_min_je_spiel[nr];\n" . " if (min == null) return;\n" @@ -13325,15 +13254,9 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void ergebnis_detailliert)) { $gelesen = array(); @@ -13380,12 +13299,9 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void $satz_werte = $gelesen; } - // Wie viele Satzzeilen angeboten werden: die Deckelung des - // SPIELS ist die Hoechstzahl der Saetze; fehlt sie, reicht - // „doppelte Siegbedingung minus eins" (best of). - // Wie viele Satzzeilen: die ausdrueckliche Wahl geht vor — - // feste Zahl N, oder 2N-1 bei N Gewinnsaetzen. Ohne Wahl wie - // bisher aus Deckelung bzw. Siegbedingung hergeleitet. + // Wie viele Satzzeilen angeboten + // werden: die Deckelung des SPIELS ist + // die Hoechstzahl der Saetze; fehlt $satz_zeilen = $saetze_wahl > 0 ? $saetze_wahl : ($saetze_wahl < 0 @@ -13395,16 +13311,8 @@ static function adminVerbandsorganMitglieder($rows,$verbandsorgan): void : ($spiel_sieg != 0 ? 2 * $spiel_sieg - 1 : 5))); $satz_zeilen = min(15, max(1, $satz_zeilen)); $satz_zeilen = max($satz_zeilen, count($satz_werte)); - // Wie viele Zeilen von Anfang an SICHTBAR sind. Alle stehen im - // Dokument; gestaffelt gezeigt wird nur, wo eine Zeile ueber - // bleiben KANN — bei einer festen Satzzahl werden alle - // gespielt, dort waere Verbergen eine Luege. - // - // Bei Gewinnsaetzen sind so viele noetig, wie zum Sieg - // gehoeren (drei bei „3 Gewinnsaetze"); die vierte und fuenfte - // erscheinen, sobald die dritte gefuellt ist. Ohne Angabe zur - // Satzzahl ist die Gesamtzahl ohnehin geraten — dann faengt es - // bei der Siegbedingung an, sonst bei einer Zeile. + // Wie viele Zeilen sichtbar sind. Alle stehen im Dokument, weil das Speichern + // spiel_1, spiel_2 ... der Reihe nach liest und beim ersten leeren Paar abbricht. $satz_min = $saetze_wahl > 0 ? $satz_zeilen : ($saetze_wahl < 0
- - -