Skip to content

Commit 2b0e51e

Browse files
JRemitzclaude
andauthored
feat: Compound penalties, slot consolidation, edit, and hotkey dialogs (#8)
Co-authored-by: Claude <noreply@anthropic.com>
1 parent 7d42716 commit 2b0e51e

9 files changed

Lines changed: 1194 additions & 73 deletions

CHANGELOG.md

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,31 @@ All notable changes to Streamn Scoreboard will be documented in this file.
44

55
## [Unreleased]
66

7+
## [0.6.0] - 2026-04-08
8+
9+
### Added
10+
- Compound penalty support (2+2, 2+5, 2+10) — two-phase penalties where phase 2 auto-starts when phase 1 expires, matching hockey rules for double-minor and major infractions
11+
- Phase 2 toggle buttons (+2, +5, +10) in the add-penalty dialog — select one for compound, deselect all for regular; only shown for sports with major penalties (hockey, lacrosse, rugby)
12+
- Compound indicator `(+M:SS)` shown in the dock UI for penalties still in phase 1
13+
- Edit button (✏) on each active penalty row — click to change remaining time
14+
- 4 new OBS hotkeys: Home/Away Penalty Edit 1/2 — opens edit dialog for the first or second running penalty
15+
- 4 new OBS hotkeys: Home/Away 2+2 Penalty Add, Home/Away 2+5 Penalty Add — open add-penalty dialog with compound phase pre-selected
16+
- `scoreboard_penalty_compact()` API — consolidates penalties to lowest slots after any clear or expiry
17+
- `scoreboard_home_penalty_set_time()` / `scoreboard_away_penalty_set_time()` API for programmatic time edits
18+
- JSON state persistence for `phase2_tenths` field (backwards compatible — old state files load with phase2 defaulting to 0)
19+
20+
### Fixed
21+
- Clock adjust at 0:00 no longer reduces penalty time — pressing -1 min or -1 sec when the period clock is already at 0:00 was incorrectly subtracting time from active penalties
22+
- File watcher re-read no longer wipes compound penalty phase 2 data — `parse_penalty_files` now preserves `phase2_tenths` across text file round-trips
23+
24+
### Changed
25+
- Penalty hotkeys now open a dialog for player number entry instead of silently adding penalties with no player number — ensures every penalty is tracked to a player
26+
- Clearing a compound penalty in phase 1 (via X button or Clear hotkey) transitions to phase 2 instead of removing the penalty entirely; clearing in phase 2 removes it as normal
27+
- Editing a compound penalty's time to 0 transitions to phase 2 instead of clearing
28+
- After clearing or expiring a penalty, remaining penalties consolidate to the lowest slots — "Clear 1" always targets the first remaining penalty regardless of which slot originally held it
29+
- Hotkey penalty-add callbacks now dispatch to the Qt main thread via `QMetaObject::invokeMethod` for thread-safe dialog display
30+
- Total OBS hotkeys increased from 37 to 45
31+
732
## [0.5.1] - 2026-03-27
833

934
### Fixed

CMakeLists.txt

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
cmake_minimum_required(VERSION 3.21)
22

3-
project(streamn_obs_scoreboard VERSION 0.5.1 LANGUAGES C CXX)
3+
project(streamn_obs_scoreboard VERSION 0.6.0 LANGUAGES C CXX)
44

55
set(CMAKE_C_STANDARD 11)
66
set(CMAKE_C_STANDARD_REQUIRED ON)

README.md

Lines changed: 10 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -15,8 +15,8 @@ OBS Studio plugin that tracks live game scoreboard state and writes it to indivi
1515
- **7 sport presets** — hockey, basketball, soccer, football, lacrosse, rugby, and generic
1616
- **17 text files** updated in real-time: clock, period, scores, shots, team names, penalties, fouls, and sport
1717
- **Dock UI** with full scoreboard controls in an OBS dock panel
18-
- **31 OBS hotkeys** for hands-free operation during broadcasts
19-
- **Penalty tracking** with automatic countdown timers (hockey, lacrosse, rugby)
18+
- **45 OBS hotkeys** for hands-free operation during broadcasts
19+
- **Penalty tracking** with automatic countdown timers, compound penalties (2+2, 2+5, 2+10), edit/clear per slot (hockey, lacrosse, rugby)
2020
- **Foul/card counters** for basketball, soccer, and football
2121
- **reeln-cli integration** for automated highlight generation
2222
- **Game event timestamps** — YouTube chapter markers copied to clipboard for livestream descriptions
@@ -138,7 +138,7 @@ Not all files are relevant for every sport — shots are only tracked for hockey
138138

139139
## Hotkeys
140140

141-
All 31 hotkeys are prefixed with "Streamn:" in OBS Settings > Hotkeys:
141+
All 45 hotkeys are prefixed with "Streamn:" in OBS Settings > Hotkeys:
142142

143143
| Hotkey | Action |
144144
|--------|--------|
@@ -149,8 +149,13 @@ All 31 hotkeys are prefixed with "Streamn:" in OBS Settings > Hotkeys:
149149
| Home/Away Goal +/- | Adjust score (4 hotkeys) |
150150
| Home/Away Shot +/- | Adjust shots (4 hotkeys) |
151151
| Period Advance / Rewind | Change period |
152-
| Home/Away Penalty Add | Add penalty with default duration |
153-
| Home/Away Penalty Clear 1/2 | Clear penalty slot (4 hotkeys) |
152+
| Home/Away Penalty Add | Open add-penalty dialog (minor) |
153+
| Home/Away Major Penalty Add | Open add-penalty dialog (major) |
154+
| Home/Away 2+2 Penalty Add | Open add-penalty dialog (compound 2+2) |
155+
| Home/Away 2+5 Penalty Add | Open add-penalty dialog (compound 2+5) |
156+
| Home/Away Penalty Clear 1/2 | Clear or transition penalty slot (4 hotkeys) |
157+
| Home/Away Penalty Edit 1/2 | Open edit dialog for penalty slot (4 hotkeys) |
158+
| Home/Away Faceoff +/- | Adjust faceoff counter (4 hotkeys) |
154159
| Generate Highlights | Trigger reeln-cli highlight generation |
155160
| Home/Away Foul +/- | Adjust foul counter (4 hotkeys) |
156161
| Home/Away Foul2 +/- | Adjust second foul counter (4 hotkeys) |

include/scoreboard-core.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -56,6 +56,7 @@ struct scoreboard_penalty {
5656
int player_number;
5757
int remaining_tenths;
5858
bool active;
59+
int phase2_tenths; /* 0 = no second phase (compound penalties) */
5960
};
6061

6162
/* Lifecycle */
@@ -166,15 +167,22 @@ void scoreboard_decrement_away_fouls2(void);
166167

167168
/* Penalties (up to SCOREBOARD_MAX_PENALTIES per team) */
168169
int scoreboard_home_penalty_add(int player_number, int duration_secs);
170+
int scoreboard_home_penalty_add_compound(int player_number, int phase1_secs,
171+
int phase2_secs);
169172
void scoreboard_home_penalty_clear(int slot);
173+
void scoreboard_home_penalty_set_time(int slot, int duration_secs);
170174
const struct scoreboard_penalty *scoreboard_get_home_penalty(int slot);
171175
int scoreboard_get_home_penalty_count(void);
172176
int scoreboard_away_penalty_add(int player_number, int duration_secs);
177+
int scoreboard_away_penalty_add_compound(int player_number, int phase1_secs,
178+
int phase2_secs);
173179
void scoreboard_away_penalty_clear(int slot);
180+
void scoreboard_away_penalty_set_time(int slot, int duration_secs);
174181
const struct scoreboard_penalty *scoreboard_get_away_penalty(int slot);
175182
int scoreboard_get_away_penalty_count(void);
176183
void scoreboard_penalty_tick(int elapsed_tenths);
177184
void scoreboard_penalty_adjust(int delta_tenths);
185+
void scoreboard_penalty_compact(void);
178186
void scoreboard_format_penalty_number(int slot, bool home, char *buf,
179187
size_t size);
180188
void scoreboard_format_penalty_time(int slot, bool home, char *buf,

0 commit comments

Comments
 (0)