Ingame-Hinweise farbig: CT blau, T gold, Sieger grün, Aufwärmphase gelb

Farbcodes kommen nur aus den Textbausteinen; Teamnamen und andere Eingaben bleiben ohne Steuerzeichen. Am Server geprüft, welche Codes CS2 im Chat als Farbe anzeigt.
This commit is contained in:
mregosar committed 2026-11-01 21:44:56 +01:00
1 parent 69fcf6d15a
commit 1fddf4d20c
3 files changed
+86 -28

No files matched your search

+59 -20
View File
@@ -4,24 +4,57 @@
const MAX_LENGTH = 120;
/**
* Text für "say", ohne Zeichen, mit denen sich weitere Konsolenbefehle anhängen ließen
* (Anführungszeichen, Semikolon, Zeilenumbrüche). Doppelpunkt und Komma bleiben für Spielstände erlaubt.
* Farbcodes für den CS2-Chat (am Server geprüft). Ein Code färbt alles bis zum nächsten Code.
* Sie kommen ausschließlich aus den Textbausteinen hier, nie aus Eingaben.
*/
export function chatText(text) {
export const COLOR = {
white: '\x01',
red: '\x02',
green: '\x04',
yellow: '\x09',
blue: '\x0B',
gold: '\x10',
};
const ALLOWED_CODES = new Set(Object.values(COLOR));
// CS2 färbt wie im Spiel: CT blau, T gold
const SIDE_COLOR = { CT: COLOR.blue, T: COLOR.gold };
/**
* Eingaben (Teamnamen, Map-Namen) für den Chat: ohne Anführungszeichen, Semikolon, Zeilenumbrüche und ohne
* Steuerzeichen, sodass sich weder Befehle anhängen noch eigene Farben einbauen lassen.
* Doppelpunkt und Komma bleiben für Spielstände erlaubt.
*/
export function chatText(text, maxLength = MAX_LENGTH) {
return String(text ?? '')
.replace(/["';\\\r\n\t]/g, '')
.replace(/[^\p{L}\p{N} .,:_\-+#!?()[\]|/&]/gu, '')
.replace(/\s+/g, ' ')
.trim()
.slice(0, MAX_LENGTH);
.slice(0, maxLength);
}
/** Konsolenbefehle für eine Liste von Hinweisen. Leere Zeilen fallen weg. */
/** Gefärbter Teil einer Zeile; danach geht es in Weiß weiter. */
const paint = (color, text) => `${color}${text}${COLOR.white}`;
/**
* Konsolenbefehle für eine Liste von Hinweisen. Erlaubt sind nur die Farbcodes aus COLOR; alles, was einen
* weiteren Befehl einleiten könnte, fällt weg. Das Leerzeichen am Anfang braucht CS2, damit der erste Farbcode wirkt.
*/
export function sayCommands(lines) {
return lines.map(chatText).filter(Boolean).map((line) => `say ${line}`);
return lines
// Kein trim(): Gelb (\x09) und Blau (\x0B) zählen für JavaScript als Leerraum und gingen sonst verloren
.map((line) => [...String(line ?? '')]
.filter((ch) => ALLOWED_CODES.has(ch) || !/[\x00-\x1F\x7F"';\\]/.test(ch))
.join(''))
.filter((line) => line.replace(/[\x00-\x1F]/g, '').trim())
.map((line) => `say ${line}`);
}
const other = (team) => (team === 'A' ? 'B' : 'A');
const name = (teams, team) => chatText(teams[team], 32) || 'Team';
/** Teamname in der Farbe seiner Startseite. */
const sided = (teams, team, ctTeam) => (ctTeam ? paint(SIDE_COLOR[team === ctTeam ? 'CT' : 'T'], name(teams, team)) : name(teams, team));
/**
* Hinweise nach dem Laden einer Map: welche Map, wer sie gewählt hat, wer welche Seite startet,
@@ -34,22 +67,24 @@ const other = (team) => (team === 'A' ? 'B' : 'A');
*/
export function mapLoadedLines({ teams, map, total, series }) {
const lines = [];
const head = total > 1 ? `Map ${map.number} von ${total}: ${map.mapName}` : `Map: ${map.mapName}`;
lines.push(map.pickedBy ? `${head} - gewählt von ${teams[map.pickedBy]}` : `${head} - Entscheidungsmap`);
const mapName = chatText(map.mapName, 32);
const head = total > 1 ? `Map ${map.number} von ${total}: ${mapName}` : `Map: ${mapName}`;
lines.push(map.pickedBy ? `${head} - gewählt von ${name(teams, map.pickedBy)}` : `${head} - Entscheidungsmap`);
if (map.ctTeam) {
const t = other(map.ctTeam);
const chooser = map.sideChosenBy ? `${teams[map.sideChosenBy]} hat die Seite gewählt: ` : '';
lines.push(`${chooser}${teams[map.ctTeam]} startet als CT, ${teams[t]} als T`);
const chooser = map.sideChosenBy ? `${name(teams, map.sideChosenBy)} hat die Seite gewählt: ` : '';
lines.push(`${chooser}${sided(teams, map.ctTeam, map.ctTeam)} startet als ${paint(COLOR.blue, 'CT')}, ${sided(teams, t, map.ctTeam)} als ${paint(COLOR.gold, 'T')}`);
}
if (total > 1) lines.push(`Serienstand: ${teams.A} ${series.A}:${series.B} ${teams.B}`);
lines.push('Aufwärmphase - das Match startet, sobald der Organisator es freigibt');
if (total > 1) lines.push(`Serienstand: ${name(teams, 'A')} ${series.A}:${series.B} ${name(teams, 'B')}`);
lines.push(paint(COLOR.yellow, 'Aufwärmphase - das Match startet, sobald der Organisator es freigibt'));
return lines;
}
/** Hinweis beim Start des Matches (Aufwärmphase beendet). */
export function matchStartLines({ teams, ctTeam }) {
if (!ctTeam) return [`Match live! ${teams.A} gegen ${teams.B} - viel Glück, have fun`];
return [`Match live! ${teams[ctTeam]} (CT) gegen ${teams[other(ctTeam)]} (T) - viel Glück, have fun`];
const live = paint(COLOR.green, 'Match live!');
if (!ctTeam) return [`${live} ${name(teams, 'A')} gegen ${name(teams, 'B')} - viel Glück, have fun`];
return [`${live} ${sided(teams, ctTeam, ctTeam)} (CT) gegen ${sided(teams, other(ctTeam), ctTeam)} (T) - viel Glück, have fun`];
}
/**
@@ -65,17 +100,21 @@ export function matchStartLines({ teams, ctTeam }) {
export function mapEndLines({ teams, map, series, decided, nextMapName, autoAdvanceSeconds, total }) {
const lines = [];
const score = `${map.score.A}:${map.score.B}`;
const mapName = chatText(map.mapName, 32);
lines.push(map.winner
? `Map ${map.number} (${map.mapName}) geht an ${teams[map.winner]} mit ${score}`
: `Map ${map.number} (${map.mapName}) endet ${score}`);
? `Map ${map.number} (${mapName}) geht an ${paint(COLOR.green, name(teams, map.winner))} mit ${score}`
: `Map ${map.number} (${mapName}) endet ${score}`);
if (decided) {
const s = decided === 'A' ? `${series.A}:${series.B}` : `${series.B}:${series.A}`;
lines.push(total > 1 ? `${teams[decided]} gewinnt die Serie ${s} - danke fürs Spielen!` : 'Danke fürs Spielen!');
lines.push(total > 1
? `${paint(COLOR.green, `${name(teams, decided)} gewinnt die Serie ${s}`)} - danke fürs Spielen!`
: 'Danke fürs Spielen!');
} else if (nextMapName) {
lines.push(`Serienstand: ${teams.A} ${series.A}:${series.B} ${teams.B}`);
const next = chatText(nextMapName, 32);
lines.push(`Serienstand: ${name(teams, 'A')} ${series.A}:${series.B} ${name(teams, 'B')}`);
lines.push(autoAdvanceSeconds >= 0
? `Nächste Map: ${nextMapName}, wird in ${autoAdvanceSeconds} s geladen - bleibt auf dem Server`
: `Nächste Map: ${nextMapName} - bleibt auf dem Server`);
? `Nächste Map: ${next}, wird in ${autoAdvanceSeconds} s geladen - bleibt auf dem Server`
: `Nächste Map: ${next} - bleibt auf dem Server`);
}
return lines;
}