From 7b1be281ea146ed39b00a3726ac084a5074334d2 Mon Sep 17 00:00:00 2001 From: WisoAltred Date: Wed, 28 Jan 2026 15:04:01 +0200 Subject: [PATCH 1/5] Change pause special character behavior (\p) to allow multiplications instead of having to spam it. Adds a parser to any numbers after a detected \p for pause chat message, matches it upto a given max to be multiplied to a given base const. (The regex will limit this to 1000 regardless, but the const is hard-coded either way.). ordered them according to the pattern in courtroom.h but it would be nicer if they were not separated. Also skips by the given amount of characters by calculating it via the text pos, so \p20 would skip 4, \p200 would skip 5, etc. Currently technically silently fails if the user tries doing -1 or \p50000 or so, so it spits out any numbers beyond the initial 4 digits to at least indicate that. --- src/courtroom.cpp | 37 ++++++++++++++++++++++++++++++++++++- src/courtroom.h | 7 +++++++ 2 files changed, 43 insertions(+), 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 7646794da..ea7b39ce4 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3506,6 +3506,31 @@ void Courtroom::handle_ic_speaking() start_chat_ticking(); } +struct PauseInfo +{ + int multiplier; + int digit_count; +}; + + +// returns multiplier and number of digits to skip +static PauseInfo parse_pause_multiplier(const QString &text, int start_pos) +{ + + // matches upto 999 (and 1000) and also prevents leading zeros + static QRegularExpression pause_regex("^([1-9]\\d{0,2}|1000)"); + QRegularExpressionMatch match = pause_regex.match(text.mid(start_pos)); + + if (match.hasMatch()) + { + int value = match.captured(1).toInt(); + int length = match.capturedLength(0); + return {value, length}; + } + + return {1, 0}; // default: multiplier=1, no digits to skip +} + QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int default_color) { QString p_text_escaped; @@ -3723,6 +3748,12 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int if (f_character == "s" || f_character == "f" || f_character == "p") // screenshake/flash/pause { skip = true; + // also skip any following digits + if (f_character == "p") + { + PauseInfo info = parse_pause_multiplier(p_text, check_pos + f_char_bytes); + check_pos += info.digit_count; + } } parse_escape_seq = false; @@ -4201,6 +4232,7 @@ void Courtroom::start_chat_ticking() tick_pos = 0; blip_ticker = 0; + pause_multiplier = 1; text_crawl = Options::getInstance().textCrawlSpeed(); blip_rate = Options::getInstance().blipRate(); blank_blip = Options::getInstance().blankBlip(); @@ -4420,6 +4452,9 @@ void Courtroom::chat_tick() if (f_character == "p") { formatting_char = true; + PauseInfo info = parse_pause_multiplier(f_message, tick_pos); + pause_multiplier = info.multiplier; + tick_pos += info.digit_count; } next_character_is_not_special = false; } @@ -4443,7 +4478,7 @@ void Courtroom::chat_tick() { if (f_character == "p") { - chat_tick_timer->start(100); // wait the pause lol + chat_tick_timer->start(pause_base_ms * pause_multiplier); } else { diff --git a/src/courtroom.h b/src/courtroom.h index dc8cdf3ae..242154803 100644 --- a/src/courtroom.h +++ b/src/courtroom.h @@ -378,6 +378,8 @@ class Courtroom : public QMainWindow int real_tick_pos = 0; // used to determine how often blips sound int blip_ticker = 0; + // pause multiplier for \p{numbers} + int pause_multiplier = 1; int blip_rate = 2; int rainbow_counter = 0; bool rainbow_appended = false; @@ -450,6 +452,11 @@ class Courtroom : public QMainWindow // amount by which we multiply the delay when we parse punctuation chars const int punctuation_modifier = 3; + // maximum pause multiplier for \p{numbers} so it does not just pause forever + const int pause_multiplier_max = 1000; + // base pause duration for a \p with no digits + const int pause_base_ms = 100; + // amount of ghost blocks int ghost_blocks = 0; From 72de2833c9921d0481530124d461ad7cfbe9325c Mon Sep 17 00:00:00 2001 From: WisoAltred Date: Wed, 28 Jan 2026 15:17:24 +0200 Subject: [PATCH 2/5] Format format --- src/courtroom.cpp | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ea7b39ce4..ca718c556 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3516,19 +3516,16 @@ struct PauseInfo // returns multiplier and number of digits to skip static PauseInfo parse_pause_multiplier(const QString &text, int start_pos) { - // matches upto 999 (and 1000) and also prevents leading zeros static QRegularExpression pause_regex("^([1-9]\\d{0,2}|1000)"); QRegularExpressionMatch match = pause_regex.match(text.mid(start_pos)); - if (match.hasMatch()) { int value = match.captured(1).toInt(); int length = match.capturedLength(0); return {value, length}; } - - return {1, 0}; // default: multiplier=1, no digits to skip + return {1, 0}; // default: multiplier=1, no digits to skip } QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int default_color) From 3bd664687c1cd17ba0faae058557b45baceee41e Mon Sep 17 00:00:00 2001 From: WisoAltred Date: Wed, 28 Jan 2026 15:18:33 +0200 Subject: [PATCH 3/5] format 2 format 2 --- src/courtroom.cpp | 1 - 1 file changed, 1 deletion(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index ca718c556..8a6dcb0d1 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3512,7 +3512,6 @@ struct PauseInfo int digit_count; }; - // returns multiplier and number of digits to skip static PauseInfo parse_pause_multiplier(const QString &text, int start_pos) { From 93cb5c987e8b4bb0781ad43750e19e6ca0aa4d41 Mon Sep 17 00:00:00 2001 From: Wiso <61384316+WisoAltred@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:10:13 +0200 Subject: [PATCH 4/5] numbers denote ms instead of multiplier also removes unnecessary variables, as well as adds validation --- src/courtroom.cpp | 62 ++++++++++++++++++++++++++--------------------- src/courtroom.h | 7 +----- 2 files changed, 36 insertions(+), 33 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 8a6dcb0d1..7dc878cd6 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3508,23 +3508,32 @@ void Courtroom::handle_ic_speaking() struct PauseInfo { - int multiplier; + int ms; int digit_count; + bool valid; }; -// returns multiplier and number of digits to skip -static PauseInfo parse_pause_multiplier(const QString &text, int start_pos) +static PauseInfo parse_pause_duration(const QString &text, int start_pos) { - // matches upto 999 (and 1000) and also prevents leading zeros - static QRegularExpression pause_regex("^([1-9]\\d{0,2}|1000)"); + static const int max_digits = QString::number(10000).length(); + static const QRegularExpression pause_regex(QString("^([1-9]\\d{0,%1})").arg(max_digits - 1)); + QRegularExpressionMatch match = pause_regex.match(text.mid(start_pos)); - if (match.hasMatch()) + if (!match.hasMatch()) { - int value = match.captured(1).toInt(); - int length = match.capturedLength(0); - return {value, length}; + return {0, 0, false}; } - return {1, 0}; // default: multiplier=1, no digits to skip + + bool ok = false; + int value = match.captured(1).toInt(&ok); + int length = match.capturedLength(0); + + if (!ok || value < 1 || value > 10000) + { + return {0, 0, false}; + } + + return {value, length, true}; } QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int default_color) @@ -3744,11 +3753,13 @@ QString Courtroom::filter_ic_text(QString p_text, bool html, int target_pos, int if (f_character == "s" || f_character == "f" || f_character == "p") // screenshake/flash/pause { skip = true; - // also skip any following digits - if (f_character == "p") + if (f_character == "p") // also skip any following digits { - PauseInfo info = parse_pause_multiplier(p_text, check_pos + f_char_bytes); - check_pos += info.digit_count; + PauseInfo info = parse_pause_duration(p_text, check_pos + f_char_bytes); + if (info.valid) + { + check_pos += info.digit_count; + } } } @@ -4228,7 +4239,6 @@ void Courtroom::start_chat_ticking() tick_pos = 0; blip_ticker = 0; - pause_multiplier = 1; text_crawl = Options::getInstance().textCrawlSpeed(); blip_rate = Options::getInstance().blipRate(); blank_blip = Options::getInstance().blankBlip(); @@ -4448,9 +4458,14 @@ void Courtroom::chat_tick() if (f_character == "p") { formatting_char = true; - PauseInfo info = parse_pause_multiplier(f_message, tick_pos); - pause_multiplier = info.multiplier; - tick_pos += info.digit_count; + PauseInfo info = parse_pause_duration(f_message, tick_pos); + if (info.valid) + { + tick_pos += info.digit_count; + real_tick_pos += f_char_length; + chat_tick_timer->start(info.ms); + return; + } } next_character_is_not_special = false; } @@ -4472,15 +4487,8 @@ void Courtroom::chat_tick() if ((msg_delay <= 0 && tick_pos < f_message.size() - 1) || formatting_char) { - if (f_character == "p") - { - chat_tick_timer->start(pause_base_ms * pause_multiplier); - } - else - { - chat_tick_timer->start(0); // Don't bother rendering anything out as we're - // doing the SPEED. (there's latency otherwise) - } + chat_tick_timer->start(0); // Don't bother rendering anything out as we're + // doing the SPEED. (there's latency otherwise) if (!formatting_char || f_character == "n" || f_character == "f" || f_character == "s" || f_character == "p") { real_tick_pos += f_char_length; // Adjust the tick position for the diff --git a/src/courtroom.h b/src/courtroom.h index 242154803..2a732b9f2 100644 --- a/src/courtroom.h +++ b/src/courtroom.h @@ -378,8 +378,6 @@ class Courtroom : public QMainWindow int real_tick_pos = 0; // used to determine how often blips sound int blip_ticker = 0; - // pause multiplier for \p{numbers} - int pause_multiplier = 1; int blip_rate = 2; int rainbow_counter = 0; bool rainbow_appended = false; @@ -452,10 +450,7 @@ class Courtroom : public QMainWindow // amount by which we multiply the delay when we parse punctuation chars const int punctuation_modifier = 3; - // maximum pause multiplier for \p{numbers} so it does not just pause forever - const int pause_multiplier_max = 1000; - // base pause duration for a \p with no digits - const int pause_base_ms = 100; + const int max_pause_duration = 10000; // amount of ghost blocks int ghost_blocks = 0; From 3dbe5685605d333204749c58375a35198e628735 Mon Sep 17 00:00:00 2001 From: Wiso <61384316+WisoAltred@users.noreply.github.com> Date: Thu, 29 Jan 2026 18:11:44 +0200 Subject: [PATCH 5/5] format 3 --- src/courtroom.cpp | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/courtroom.cpp b/src/courtroom.cpp index 7dc878cd6..24164f2d4 100644 --- a/src/courtroom.cpp +++ b/src/courtroom.cpp @@ -3517,22 +3517,18 @@ static PauseInfo parse_pause_duration(const QString &text, int start_pos) { static const int max_digits = QString::number(10000).length(); static const QRegularExpression pause_regex(QString("^([1-9]\\d{0,%1})").arg(max_digits - 1)); - QRegularExpressionMatch match = pause_regex.match(text.mid(start_pos)); if (!match.hasMatch()) { return {0, 0, false}; } - bool ok = false; int value = match.captured(1).toInt(&ok); int length = match.capturedLength(0); - if (!ok || value < 1 || value > 10000) { return {0, 0, false}; } - return {value, length, true}; }