diff --git a/TODO b/TODO index b71f99822e..9196b3c548 100644 --- a/TODO +++ b/TODO @@ -12,6 +12,11 @@ FBGM show field during game - some minimum height of field, but expand dynamically for long drives - draw vertical lines for scrimmage and togo - light mode + - how to update numPlays + - accepted penalties only count as a play if they are added on to the end of the play. this means we sometimes need to decrease numPlays when a penalty gets accepted, but not always + - how does drive tracker handle turnover reversed on penalty? + - need to set sportState.drive to undefined when doing a kickoff at start of half/overtime + - unify logic with kickoffAfterEndOfPeriod use team colors as foreground/background in UI in some places - already guaranteed contrast bc used for jersey numbers - box scores diff --git a/src/ui/components/BoxScore.football.tsx b/src/ui/components/BoxScore.football.tsx index 337126a833..8a00ffe0da 100644 --- a/src/ui/components/BoxScore.football.tsx +++ b/src/ui/components/BoxScore.football.tsx @@ -15,6 +15,7 @@ import updateSortBys from "./DataTable/updateSortBys"; import { getSortClassName } from "./DataTable/Header"; import range from "lodash-es/range"; import classNames from "classnames"; +import type { SportState } from "../util/processLiveGameEvents.football"; type Quarter = `Q${number}` | "OT"; @@ -386,20 +387,31 @@ const ScoringSummary = memo( }, ); -const FieldAndDrive = ({ boxScore }: { boxScore: BoxScore }) => { - const t = 0; - const t2 = 1; +const FieldAndDrive = ({ + boxScore, + sportState, +}: { + boxScore: BoxScore; + sportState: SportState; +}) => { + const t = sportState.t; + const t2 = t === 0 ? 1 : 0; // 12 is for 2 endzones and 10 10-yard areas in between const NUM_SECTIONS = 12; - const DEFAULT_HEIGHT = 200; - console.log(boxScore); + + const yards = sportState.scrimmage - sportState.initialScrimmage; + return (
-
- LOGO 1st & 10, own 20 -
Drive: 5 plays, 62 yards
+
+ {sportState.text} +
+ Drive: {sportState.numPlays} play + {sportState.numPlays === 1 ? "" : "s"}, {yards} yard + {yards === 1 ? "" : "s"} +
{ ); }; -const BoxScore = ({ boxScore, Row }: { boxScore: BoxScore; Row: any }) => { +const BoxScore = ({ + boxScore, + sportState, + Row, +}: { + boxScore: BoxScore; + sportState: SportState; + Row: any; +}) => { const liveGameSim = (boxScore as any).won?.name === undefined; return (
- {liveGameSim ? : undefined} + {liveGameSim ? ( + + ) : undefined}

Scoring Summary

{ let stop = false; let text; @@ -86,8 +106,9 @@ const processLiveGameEvents = ({ boxScore.time = e.time; stop = true; } else if (e.type === "clock") { - if (typeof e.awaitingKickoff === "number") { - text = `${e.time} - ${boxScore.teams[actualT].abbrev} kicking off`; + let textWithoutTime; + if (e.awaitingKickoff !== undefined) { + textWithoutTime = `${boxScore.teams[actualT].abbrev} kicking off`; } else { let fieldPos = ""; if (e.scrimmage === 50) { @@ -98,13 +119,26 @@ const processLiveGameEvents = ({ fieldPos = `own ${e.scrimmage}`; } - text = `${e.time} - ${ + textWithoutTime = `${ boxScore.teams[actualT].abbrev } ball, ${helpers.ordinal(e.down)} & ${e.toGo}, ${fieldPos}`; } + text = `${e.time} - ${textWithoutTime}`; boxScore.time = e.time; stop = true; + + if (e.awaitingKickoff !== undefined || sportState.t !== actualT) { + sportState.t = actualT; + sportState.numPlays = 0; + sportState.initialScrimmage = e.scrimmage; + sportState.scrimmage = e.scrimmage; + sportState.plays = []; + sportState.text = textWithoutTime; + } else { + sportState.text = textWithoutTime; + sportState.scrimmage = e.scrimmage; + } } else if (e.type === "stat") { // Quarter-by-quarter score if (e.s === "pts") { @@ -148,6 +182,7 @@ const processLiveGameEvents = ({ overtimes, possessionChange, quarters, + sportState, text, }; }; diff --git a/src/ui/util/processLiveGameEvents.ts b/src/ui/util/processLiveGameEvents.ts index 6cc96d50a9..7441551204 100644 --- a/src/ui/util/processLiveGameEvents.ts +++ b/src/ui/util/processLiveGameEvents.ts @@ -25,7 +25,7 @@ const processLiveGameEvents = ({ overtimes, quarters, sportState, - }) as any, + }), basketball: processLiveGameEventsBasketball({ events, boxScore, @@ -37,6 +37,7 @@ const processLiveGameEvents = ({ boxScore, overtimes, quarters, + sportState, }), hockey: processLiveGameEventsHockey({ events, diff --git a/src/ui/views/LiveGame.tsx b/src/ui/views/LiveGame.tsx index baab22b7f9..8e51c6a77e 100644 --- a/src/ui/views/LiveGame.tsx +++ b/src/ui/views/LiveGame.tsx @@ -19,7 +19,8 @@ import { helpers, processLiveGameEvents, toWorker } from "../util"; import type { View } from "../../common/types"; import { bySport, getPeriodName, isSport } from "../../common"; import useLocalStorageState from "use-local-storage-state"; -import type { SportState } from "../util/processLiveGameEvents.baseball"; +import { DEFAULT_SPORT_STATE as DEFAULT_SPORT_STATE_BASEBALL } from "../util/processLiveGameEvents.baseball"; +import { DEFAULT_SPORT_STATE as DEFAULT_SPORT_STATE_FOOTBALL } from "../util/processLiveGameEvents.football"; import { HeadlineScore } from "../components/BoxScoreWrapper"; type PlayerRowProps = { @@ -92,20 +93,12 @@ const getSeconds = (time: string | undefined) => { return min * 60 + sec; }; -export const DEFAULT_SPORT_STATE = isSport("baseball") - ? ({ - bases: [undefined, undefined, undefined] as [ - number | undefined, - number | undefined, - number | undefined, - ], - outs: 0, - balls: 0, - strikes: 0, - batterPid: -1, - pitcherPid: -1, - } as SportState) - : undefined; +const DEFAULT_SPORT_STATE = bySport({ + baseball: DEFAULT_SPORT_STATE_BASEBALL, + basketball: undefined, + football: DEFAULT_SPORT_STATE_FOOTBALL, + hockey: undefined, +}); export const LiveGame = (props: View<"liveGame">) => { const [paused, setPaused] = useState(false); @@ -251,10 +244,13 @@ export const LiveGame = (props: View<"liveGame">) => { if (events.current && events.current.length > 0) { if (!pausedRef.current) { - setTimeout(() => { - processToNextPause(); - setPlayIndex(prev => prev + 1); - }, 4000 / 1.2 ** speedRef.current); + setTimeout( + () => { + processToNextPause(); + setPlayIndex(prev => prev + 1); + }, + 4000 / 1.2 ** speedRef.current, + ); } } else { boxScore.current.time = "0:00"; @@ -547,7 +543,9 @@ export const LiveGame = (props: View<"liveGame">) => { label: "Next baserunner", key: "T", onClick: () => { - const initialBases = sportState.current?.bases ?? []; + const sportStateBaseball = + sportState.current as typeof DEFAULT_SPORT_STATE_BASEBALL; + const initialBases = sportStateBaseball.bases ?? []; const initialBaserunners = new Set( initialBases.filter(pid => pid !== undefined), ); @@ -562,7 +560,7 @@ export const LiveGame = (props: View<"liveGame">) => { numPlays += 1; // Any new baserunner -> stop - const baserunners = (sportState.current?.bases ?? []).filter( + const baserunners = (sportStateBaseball.bases ?? []).filter( pid => pid !== undefined, ); if (baserunners.length === 0) {