Beispiele
Jedes Skript hier wird entweder mit der App ausgeliefert oder ist aus Teilen gebaut, die mitgeliefert werden. Kopier eines, füg es in das darüber genannte Feld ein und pass es an.
Texte auf dem Timer-Bildschirm
Abschnitt betitelt „Texte auf dem Timer-Bildschirm“Diese kommen in das Feld Wert eines Inhalts.
Der Countdown
Abschnitt betitelt „Der Countdown“{{ (secondsLeftInLevel * 1000).toCompactTimeDurationString }}secondsLeftInLevel sind Sekunden, und die Zeitspannen-Formatierer lesen Millisekunden, deshalb wird zuerst mit 1000 multipliziert. toCompactTimeDurationString ergibt 20:00, toTimeDurationString würde 0:20:00 ergeben.
Levelnummer, die Pausen ignoriert
Abschnitt betitelt „Levelnummer, die Pausen ignoriert“Level {{ blindLevelNumber }} von {{ blindLevelCount }}Mit der Bedingung isBlindsLevel, damit die Zeile während einer Pause verschwindet, statt auf dem gerade beendeten Level einzufrieren.
Blinds, kompakt
Abschnitt betitelt „Blinds, kompakt“{{ (currentLevel.smallBlind).toCompactDecimalString + " / " + (currentLevel.bigBlind).toCompactDecimalString }}toCompactDecimalString macht auf Englisch aus 1500 ein 1.5K, was verhindert, dass große Stapel die Zelle sprengen.
Durchschnittlicher Stack in Big Blinds
Abschnitt betitelt „Durchschnittlicher Stack in Big Blinds“{{ (averageChipsPerPlayer / activeBigBlind).round }} BBsGib dem Ganzen die Bedingung activeBigBlind > 0, damit nicht durch null geteilt wird, bevor die Blinds anfangen.
Voraussichtliche Endzeit
Abschnitt betitelt „Voraussichtliche Endzeit“endet gegen {{ (now() + estimatedSecondsUntilEnd * 1000).round.toHMTimeString }}now() sind Millisekunden, deshalb wird die Schätzung passend umgerechnet und dann als Uhrzeit formatiert. Gib ihr die Bedingung isTimerRunning, denn bei pausierter Uhr ist die Schätzung sinnlos.
Chip Leader
Abschnitt betitelt „Chip Leader“{{ chipLeaders.take(3).map(func(p) { p.shortName + " — " + p.currentChips.round.toCompactDecimalString }).join("\n") }}chipLeaders sind die aktiven Spieler mit gemeldetem Chipstand, meiste Chips zuerst, take(3) liefert also die Top drei; map macht aus jedem eine Zeile „Name — Stapel“ und join stapelt sie untereinander. Bedingung: chipLeaders.isNotEmpty.
Beste Hand
Abschnitt betitelt „Beste Hand“{{ cards = highHand.pokerHandToCards; highHandPlayer.shortName + " — " + cards.pokerCardsToHandName + " " + cards.pokerCardsToText }}Zwei Anweisungen in einer Zeile, getrennt durch ;, weil eine Vorlage in ein Klammernpaar passen muss. Die erste entschlüsselt die Hand in Karten, die zweite baut die Zeile. Bedingung: hasHighHand.
Ranglisten
Abschnitt betitelt „Ranglisten“Der Trick bei einer Rangliste ist where zum Filtern, sort mit negiertem Schlüssel zum Ordnen, take zum Abschneiden und join("\n"), um die Ergebnisse zu einer Spalte zu stapeln.
Top fünf Knockouts
Abschnitt betitelt „Top fünf Knockouts“{{eliminators = players.where(func(p) { p.totalEliminated > 0 }).sort(func(p) { -p.totalEliminated })eliminators.take(5).map(func(p) { p.shortName }).join("\n")+ if (eliminators.count > 5) { "\n…" } else { "" }}}Das if am Ende hängt drei Punkte an, wenn mehr Spieler da sind als hineinpassen, und hängt nichts an, wenn nicht, denn if liefert so oder so einen Wert.
Die Zahlenspalte daneben ist dasselbe Skript mit zwei Änderungen: p.totalEliminated statt p.shortName, und ein blankes "\n" statt "\n…":
{{eliminators = players.where(func(p) { p.totalEliminated > 0 }).sort(func(p) { -p.totalEliminated })eliminators.take(5).map(func(p) { p.totalEliminated }).join("\n")+ if (eliminators.count > 5) { "\n" } else { "" }}}Nur die Namensspalte bekommt die drei Punkte, die Zahlenspalte hängt bloß die Leerzeile an. So bleiben beide Spalten gleich hoch und ihre Zeilen fluchten.
Endplatzierung
Abschnitt betitelt „Endplatzierung“Das eingebaute Widget Punkte, in zwei Spalten. playersEliminated ist bereits nach Platz sortiert, und der Sieger ist der eine aktive Spieler mit einer Platzierung, wird also vorangestellt, sobald das Turnier vorbei ist: take einer bedingten Anzahl fügt ihn dann hinzu und jetzt noch nicht.
{{scored = playersActive.take(if (isPostgame) { 1 } else { 0 }) + playersEliminatedscored.take(10).map(func(p) { p.shortName }).join("\n")+ if (scored.count > 10) { "\n…" } else { "" }}}Die Punktespalte daneben tauscht p.shortName gegen p.points und die Auslassungspunkte gegen ein schlichtes "\n":
{{scored = playersActive.take(if (isPostgame) { 1 } else { 0 }) + playersEliminatedscored.take(10).map(func(p) { p.points }).join("\n")+ if (scored.count > 10) { "\n" } else { "" }}}p.points führt deine eigene Punkteformel aus, hier steht also keine Wertung, die du mit ihr abgleichen müsstest.
Top zehn Kopfgeld-Gewinner
Abschnitt betitelt „Top zehn Kopfgeld-Gewinner“{{winners = players.where(func(p) { p.bountyChipWinnings > 0 }).sort(func(p) { -p.bountyChipWinnings })winners.take(10).map(func(p) { p.shortName }).join("\n")+ if (winners.count > 10) { "\n…" } else { "" }}}Die Gewinnspalte dazu funktioniert genauso: p.bountyChipWinnings.toCurrencyString für den Betrag, und "\n" ohne die drei Punkte.
Eine Auszahlungsspalte
Abschnitt betitelt „Eine Auszahlungsspalte“Die einfachste Fassung der Auszahlungsliste sind drei Inhalte nebeneinander. Die Plätze:
{{ i = 0; payouts.take(payoutsToShow).map(func(e) { i = i + 1; i.withOrdinalSuffix }).join("\n") }}withOrdinalSuffix ist fest englisch und ergibt 1st, 2nd, 3rd. Für deutsche Platzierungen nimmst du stattdessen:
{{ i = 0; payouts.take(payoutsToShow).map(func(e) { i = i + 1; i.toString + "." }).join("\n") }}Die Beträge:
{{ payouts.take(payoutsToShow).map(func(e) { e.toCurrencyString }).join("\n") }}Und sobald Spieler fertig sind, ihre Namen:
{{ playersWithPayouts.map(func(p) { p.shortName }).join("\n") }}Das eingebaute Widget Auszahlungen benutzt längere Fassungen dieser drei, die die noch offenen Plätze mit den fertigen Spielern zusammenführen und die jüngsten Knockouts unter einer Leerzeile anhängen. Die lohnen einen Blick, sobald du dich sicher fühlst, aber diese drei sind das Muster.
Bedingungen
Abschnitt betitelt „Bedingungen“Bedingungen kommen in das Feld Bedingung eines Inhalts oder an eine Zeile oder Spalte in Layout & Inhalt.
totalCollected > 0currentLevel.bigBlind > 0 || currentLevel.ante > 0levelIndex + 1 < levels.lengthuseBountyChips && players.where(func(p) { p.bountyChipWinnings > 0 }).count > 0Das sind die echten Bedingungen der eingebauten Widgets Auszahlungen, Blinds und Antes, Nächstes Level und Pause sowie Kopfgelder.
Warnungen
Abschnitt betitelt „Warnungen“Die Bedingung einer Warnung wird etwa einmal pro Sekunde geprüft, und die Warnung löst jedes Mal aus, wenn sie wahr ist. becameTrue(...), changed(...) und was(...) sind das, was aus „zehn Minuten lang wahr“ ein „in genau diesem Moment wahr“ macht.
Einmal auslösen, sobald etwas erstmals wahr wird
Abschnitt betitelt „Einmal auslösen, sobald etwas erstmals wahr wird“becameTrue(currentPlayerCount == 3)becameTrue(currentLevel.bigBlind >= 100)Eine Minute Restzeit in einem Blind-Level
Abschnitt betitelt „Eine Minute Restzeit in einem Blind-Level“becameTrue(secondsLeftInLevel <= 60) && currentLevel.isBlindLevelDas ist die eingebaute Warnung nahe dem Ende des Levels. Ohne das becameTrue würde sie sechzigmal auslösen.
Gerade ist jemand ausgeschieden
Abschnitt betitelt „Gerade ist jemand ausgeschieden“currentPlayerCount < was(currentPlayerCount)was(x) gibt dir den Wert selbst von vor einer Sekunde, für Vergleiche, die die beiden anderen nicht direkt ausdrücken — hier, dass die Anzahl gesunken und nicht bloß anders ist.
Die Blinds sind gestiegen
Abschnitt betitelt „Die Blinds sind gestiegen“(changed(levelIndex) || becameTrue(isInGame)) && currentLevel.isBlindLevel && currentLevel.bigBlind > 0Das ist die eingebaute Warnung Blinds geändert. Die erste Hälfte ist der Levelwechsel, die zweite der Beginn des Spiels — auch das ist eine Änderung der Blinds, nämlich von nichts auf die Startblinds. Diese Hälfte ist es, die die Blinds in einer Struktur ohne Vorlauflevel ansagt: Dort startet der Timer auf dem ersten Blind-Level und wechselt somit nie darauf.
Mit diesem TTS-Text:
Der Small Blind beträgt {{ currentLevel.smallBlind }}, und der Big Blind beträgt {{ currentLevel.bigBlind }}Jemand ist ausgeschieden
Abschnitt betitelt „Jemand ist ausgeschieden“if log.entries.isEmpty { false } else { e = log.entries.last e.type == "knockout" && e.status == "enabled" && changed(log.entries.last.dt)}Die isEmpty-Absicherung kommt zuerst, weil .last auf einem leeren Protokoll fehlschlagen würde. changed(...) auf dem dt des Eintrags ist das, was ein erneutes Auslösen beim selben Knockout verhindert, und es steht am Ende, damit die Typprüfung zuerst läuft. Beachte, dass dort ausgeschrieben log.entries.last.dt steht statt e: Diese Funktionen lesen Turnierwerte erneut, und e hast du selbst zugewiesen.
Der zugehörige TTS-Text nennt alle Beteiligten:
Es ist ein Knockout! {{ e = log.entries.last; e.players.map(func(p) { p.toPlayer().name }).join(", ", ", and ") }}, ausgeknockt von {{ e.byPlayers.map(func(p) { p.toPlayer().name }).join(", ", ", and ") }}!join(", ", ", and ") gibt dem letzten Namen ein eigenes Trennzeichen, sodass drei Namen als „Alice, Bob, and Carol“ gelesen werden statt als „Alice, Bob, Carol“.
Auszahlungsstrukturen
Abschnitt betitelt „Auszahlungsstrukturen“Diese kommen in Auszahlungen → Skript. Das Ergebnis muss eine Liste von Beträgen sein; ihre Länge bestimmt, wie viele Plätze bezahlt werden.
Mehr Plätze, wenn das Feld wächst
Abschnitt betitelt „Mehr Plätze, wenn das Feld wächst“places = 1 + totalBuyIns / 5defaultPayoutPercentages(places).map(func(p) { p * netPrize })Ein bezahlter Platz je fünf Buy-ins, aufgeteilt nach den Prozentsätzen der App.
if totalBuyIns < 10 { [100, 60, 40] }else if totalBuyIns < 17 { [150, 90, 60] }else { [180, 110, 70, 40] }Feste Beträge statt Prozentsätze, wobei ab siebzehn Buy-ins ein vierter Platz dazukommt.
Einen festen Betrag für Platz drei zurückhalten
Abschnitt betitelt „Einen festen Betrag für Platz drei zurückhalten“[0.55 * (netPrize - 50), 0.45 * (netPrize - 50), 50]Platz drei bekommt immer 50, die oberen beiden teilen den Rest 55/45.
Die Auszahlungstabelle deiner Liga
Abschnitt betitelt „Die Auszahlungstabelle deiner Liga“table = [ [90, 30], [110, 40], [130, 50], [150, 60], [160, 60, 20], [170, 70, 30]]n = totalBuyIns + totalRebuystable[min(max(n, 4), 9) - 4]Eine Zeile pro Teilnehmerzahl, beginnend bei vier. Die letzte Zeile begrenzt die Anzahl auf den Bereich, den die Tabelle abdeckt, und greift die passende Zeile heraus. Zeilen dürfen unterschiedlich lang sein, die Zahl der bezahlten Plätze ändert sich also im Verlauf der Tabelle. Erweitere sie Zeile für Zeile.
Ligapunkte
Abschnitt betitelt „Ligapunkte“Diese kommen in Statistiken → Spielerpunktformel und werden einmal pro Spieler ausgewertet, wobei playerId auf diesen Spieler zeigt.
Die eingebaute Formel, mit zwei Alternativen als Kommentar:
player = playerId.toPlayer()p = player.placee = player.totalEliminatedc = totalPlayerCountt = totalCollectedpoints = 0
// Linear// points = c - p + 1
// Square root// points = sqrt(c + 1) / p * 10
// Logarithmicpoints = ln(c + 1) / p * 10
points.roundTausch, welche Zeile auskommentiert ist, um die Kurve zu ändern. Linear gibt einen Punkt für jeden Spieler, den du überdauert hast; logarithmisch, die Voreinstellung, belohnt die vordersten Plätze deutlich stärker.
Um Knockouts einzurechnen, addierst du sie dazu:
points = ln(c + 1) / p * 10 + e * 2points.roundDieselbe Formel summieren die Club-Statistiken über eine Saison. Änderst du sie, ändert sich also auch die Saison-Rangliste.