diff --git a/field/arena.go b/field/arena.go index 10bacea5..10f91fc6 100644 --- a/field/arena.go +++ b/field/arena.go @@ -917,165 +917,303 @@ func (arena *Arena) getAssignedAllianceStation(teamId int) string { return "" } - +var redAmplifiedTimePostWindow_ons = false +var blueAmplifiedTimePostWindow_ons = false // Updates the score given new input information from the field PLC, and actuates PLC outputs accordingly. func (arena *Arena) handlePlcInputOutput() { if !arena.Plc.IsEnabled() { - return - } - - // Handle PLC functions that are always active. - if arena.Plc.GetFieldEStop() && !arena.matchAborted { - arena.AbortMatch() - } - redEStops, blueEStops := arena.Plc.GetTeamEStops() - redAStops, blueAStops := arena.Plc.GetTeamAStops() - arena.handleTeamStop("R1", redEStops[0], redAStops[0]) - arena.handleTeamStop("R2", redEStops[1], redAStops[1]) - arena.handleTeamStop("R3", redEStops[2], redAStops[2]) - arena.handleTeamStop("B1", blueEStops[0], blueAStops[0]) - arena.handleTeamStop("B2", blueEStops[1], blueAStops[1]) - arena.handleTeamStop("B3", blueEStops[2], blueAStops[2]) - redEthernets, blueEthernets := arena.Plc.GetEthernetConnected() - arena.AllianceStations["R1"].Ethernet = redEthernets[0] - arena.AllianceStations["R2"].Ethernet = redEthernets[1] - arena.AllianceStations["R3"].Ethernet = redEthernets[2] - arena.AllianceStations["B1"].Ethernet = blueEthernets[0] - arena.AllianceStations["B2"].Ethernet = blueEthernets[1] - arena.AllianceStations["B3"].Ethernet = blueEthernets[2] - - // Handle in-match PLC functions. - redScore := &arena.RedRealtimeScore.CurrentScore - oldRedScore := *redScore - oldRedAmplifiedTimeRemainingSec := arena.RedRealtimeScore.AmplifiedTimeRemainingSec - blueScore := &arena.BlueRealtimeScore.CurrentScore - oldBlueScore := *blueScore - oldBlueAmplifiedTimeRemainingSec := arena.BlueRealtimeScore.AmplifiedTimeRemainingSec - matchStartTime := arena.MatchStartTime - currentTime := time.Now() - teleopGracePeriod := matchStartTime.Add( - game.GetDurationToTeleopEnd() + game.SpeakerTeleopGracePeriodSec*time.Second, - ) - inGracePeriod := arena.MatchState == PostMatch && currentTime.Before(teleopGracePeriod) && !arena.matchAborted - - redAllianceReady := arena.checkAllianceStationsReady("R1", "R2", "R3") == nil - blueAllianceReady := arena.checkAllianceStationsReady("B1", "B2", "B3") == nil - - // Handle the evergreen PLC functions: stack lights, stack buzzer, and field reset light. - switch arena.MatchState { - case PreMatch: - if arena.lastMatchState != PreMatch { - arena.Plc.SetFieldResetLight(true) + // Declare and initialize arrays + redEStops, blueEStops := [3]bool{}, [3]bool{} + redAStops, blueAStops := [3]bool{}, [3]bool{} + // Fill arrays with false values + for i := range redEStops { + redEStops[i] = false + redAStops[i] = false } - fallthrough - case TimeoutActive: - fallthrough - case PostTimeout: - // Set the stack light state -- solid alliance color(s) if robots are not connected, solid orange if scores are - // not input, or blinking green if ready. - greenStackLight := redAllianceReady && blueAllianceReady && arena.Plc.GetCycleState(2, 0, 2) - arena.Plc.SetStackLights(!redAllianceReady, !blueAllianceReady, false, greenStackLight) - arena.Plc.SetStackBuzzer(redAllianceReady && blueAllianceReady) - - // Turn off lights if all teams become ready. - if redAllianceReady && blueAllianceReady { - arena.FieldReset = false - arena.Plc.SetFieldResetLight(false) - if arena.CurrentMatch.FieldReadyAt.IsZero() { - arena.CurrentMatch.FieldReadyAt = time.Now() + for i := range blueEStops { + blueEStops[i] = false + blueAStops[i] = false + } + arena.handleTeamStop("R1", redEStops[0], redAStops[0]) + arena.handleTeamStop("R2", redEStops[1], redAStops[1]) + arena.handleTeamStop("R3", redEStops[2], redAStops[2]) + arena.handleTeamStop("B1", blueEStops[0], blueAStops[0]) + arena.handleTeamStop("B2", blueEStops[1], blueAStops[1]) + arena.handleTeamStop("B3", blueEStops[2], blueAStops[2]) + + // Handle in-match PLC functions. + redScore := &arena.RedRealtimeScore.CurrentScore + oldRedScore := *redScore + blueScore := &arena.BlueRealtimeScore.CurrentScore + oldBlueScore := *blueScore + matchStartTime := arena.MatchStartTime + currentTime := time.Now() + teleopGracePeriod := matchStartTime.Add( + game.GetDurationToTeleopEnd() + game.SpeakerTeleopGracePeriodSec*time.Second, + ) + inGracePeriod := arena.MatchState == PostMatch && currentTime.Before(teleopGracePeriod) + + redAllianceReady := arena.checkAllianceStationsReady("R1", "R2", "R3") == nil + blueAllianceReady := arena.checkAllianceStationsReady("B1", "B2", "B3") == nil + + // Handle the evergreen PLC functions: stack lights, stack buzzer, and field reset light. + switch arena.MatchState { + case PreMatch: + if arena.lastMatchState != PreMatch { + //*arena.Plc.SetFieldResetLight(true) + } + fallthrough + case TimeoutActive: + fallthrough + case PostTimeout: + // Set the stack light state -- solid alliance color(s) if robots are not connected, solid orange if scores are + // not input, or blinking green if ready. + //*greenStackLight := redAllianceReady && blueAllianceReady //&& arena.Plc.GetCycleState(2, 0, 2) + //*arena.Plc.SetStackLights(!redAllianceReady, !blueAllianceReady, false, greenStackLight) + //*arena.Plc.SetStackBuzzer(redAllianceReady && blueAllianceReady) + + // Turn off lights if all teams become ready. + if redAllianceReady && blueAllianceReady { + arena.FieldReset = false + //*arena.Plc.SetFieldResetLight(false) + if arena.CurrentMatch.FieldReadyAt.IsZero() { + arena.CurrentMatch.FieldReadyAt = time.Now() + } + } + case PostMatch: + if arena.FieldReset { + //*arena.Plc.SetFieldResetLight(true) } + //*scoreReady := arena.RedRealtimeScore.FoulsCommitted && arena.BlueRealtimeScore.FoulsCommitted && + //* arena.alliancePostMatchScoreReady("red") && arena.alliancePostMatchScoreReady("blue") + //*arena.Plc.SetStackLights(false, false, !scoreReady, false) + case AutoPeriod, PausePeriod, TeleopPeriod: + //*arena.Plc.SetStackBuzzer(false) + //*arena.Plc.SetStackLights(!redAllianceReady, !blueAllianceReady, false, true) } - case PostMatch: - if arena.FieldReset { - arena.Plc.SetFieldResetLight(true) + + // Get all the game-specific inputs and update the score. + redAmplifyButton, redCoopButton, blueAmplifyButton, blueCoopButton := false, false, false, false + redAmpNoteCount := arena.RedRealtimeScore.CurrentScore.AmpSpeaker.AutoAmpNotes + + arena.RedRealtimeScore.CurrentScore.AmpSpeaker.TeleopAmpNotes + redSpeakerNoteCount := arena.RedRealtimeScore.CurrentScore.AmpSpeaker.AutoSpeakerNotes + + arena.RedRealtimeScore.CurrentScore.AmpSpeaker.TeleopUnamplifiedSpeakerNotes + + arena.RedRealtimeScore.CurrentScore.AmpSpeaker.TeleopAmplifiedSpeakerNotes + blueAmpNoteCount := arena.BlueRealtimeScore.CurrentScore.AmpSpeaker.AutoAmpNotes + + arena.BlueRealtimeScore.CurrentScore.AmpSpeaker.TeleopAmpNotes + blueSpeakerNoteCount := arena.BlueRealtimeScore.CurrentScore.AmpSpeaker.AutoSpeakerNotes + + arena.BlueRealtimeScore.CurrentScore.AmpSpeaker.TeleopUnamplifiedSpeakerNotes + + arena.BlueRealtimeScore.CurrentScore.AmpSpeaker.TeleopAmplifiedSpeakerNotes + + redAmpSpeaker := &arena.RedRealtimeScore.CurrentScore.AmpSpeaker + blueAmpSpeaker := &arena.BlueRealtimeScore.CurrentScore.AmpSpeaker + redAmpSpeaker.UpdateState( + redAmpNoteCount, redSpeakerNoteCount, redAmplifyButton, redCoopButton, matchStartTime, currentTime, + ) + blueAmpSpeaker.UpdateState( + blueAmpNoteCount, blueSpeakerNoteCount, blueAmplifyButton, blueCoopButton, matchStartTime, currentTime, + ) + if !oldRedScore.Equals(redScore) || !oldBlueScore.Equals(blueScore) { + arena.RealtimeScoreNotifier.Notify() } - scoreReady := arena.RedRealtimeScore.FoulsCommitted && arena.BlueRealtimeScore.FoulsCommitted && - arena.alliancePostMatchScoreReady("red") && arena.alliancePostMatchScoreReady("blue") - arena.Plc.SetStackLights(false, false, !scoreReady, false) - case AutoPeriod, PausePeriod, TeleopPeriod: - arena.Plc.SetStackBuzzer(false) - arena.Plc.SetStackLights(!redAllianceReady, !blueAllianceReady, false, true) - } - // Get all the game-specific inputs and update the score. - redAmplifyButton, redCoopButton, blueAmplifyButton, blueCoopButton := arena.Plc.GetAmpButtons() - var redAmpNoteCount, redSpeakerNoteCount, blueAmpNoteCount, blueSpeakerNoteCount int - if arena.MatchState != PreMatch { - // Don't read the registers pre-match to avoid messing up the amp/speaker state from any manual testing. - redAmpNoteCount, redSpeakerNoteCount, blueAmpNoteCount, blueSpeakerNoteCount = - arena.Plc.GetAmpSpeakerNoteCounts() - } - redAmpSpeaker := &arena.RedRealtimeScore.CurrentScore.AmpSpeaker - blueAmpSpeaker := &arena.BlueRealtimeScore.CurrentScore.AmpSpeaker - redAmpSpeaker.UpdateState( - redAmpNoteCount, - redSpeakerNoteCount, - redAmplifyButton, - redCoopButton, - matchStartTime, - currentTime, - arena.CurrentMatch.Type == model.Playoff, - ) - blueAmpSpeaker.UpdateState( - blueAmpNoteCount, - blueSpeakerNoteCount, - blueAmplifyButton, - blueCoopButton, - matchStartTime, - currentTime, - arena.CurrentMatch.Type == model.Playoff, - ) - redAmplifiedTimeRemaining := redAmpSpeaker.AmplifiedTimeRemaining(currentTime) - arena.RedRealtimeScore.AmplifiedTimeRemainingSec = int(math.Ceil(redAmplifiedTimeRemaining)) - blueAmplifiedTimeRemaining := blueAmpSpeaker.AmplifiedTimeRemaining(currentTime) - arena.BlueRealtimeScore.AmplifiedTimeRemainingSec = int(math.Ceil(blueAmplifiedTimeRemaining)) - if !oldRedScore.Equals(redScore) || !oldBlueScore.Equals(blueScore) || - oldRedAmplifiedTimeRemainingSec != arena.RedRealtimeScore.AmplifiedTimeRemainingSec || - oldBlueAmplifiedTimeRemainingSec != arena.BlueRealtimeScore.AmplifiedTimeRemainingSec { - arena.RealtimeScoreNotifier.Notify() - } - - // Handle the amp outputs. - if arena.MatchState == AutoPeriod || arena.MatchState == PausePeriod || arena.MatchState == TeleopPeriod { - redLowAmpLight := redAmpSpeaker.BankedAmpNotes >= 1 - redHighAmpLight := redAmpSpeaker.BankedAmpNotes >= 2 - redCoopAmpLight := redAmpSpeaker.CoopActivated - if redAmplifiedTimeRemaining > 0 { - redLowAmpLight = int(redAmplifiedTimeRemaining*4)%2 == 0 - redHighAmpLight = !redLowAmpLight + // Handle the amp outputs. + redAmplifiedTimeRemaining := redAmpSpeaker.AmplifiedTimeRemaining(currentTime) + arena.RedRealtimeScore.AmplifiedTimeRemainingSec = int(redAmplifiedTimeRemaining) + redAmplifiedTimePostWindow := redAmpSpeaker.IsAmplified(currentTime, true) + arena.RedRealtimeScore.AmplifiedTimePostWindow = redAmplifiedTimePostWindow + + blueAmplifiedTimeRemaining := blueAmpSpeaker.AmplifiedTimeRemaining(currentTime) + arena.BlueRealtimeScore.AmplifiedTimeRemainingSec = int(blueAmplifiedTimeRemaining) + blueAmplifiedTimePostWindow := blueAmpSpeaker.IsAmplified(currentTime, true) + arena.BlueRealtimeScore.AmplifiedTimePostWindow = blueAmplifiedTimePostWindow + + if arena.MatchState == AutoPeriod || arena.MatchState == PausePeriod || arena.MatchState == TeleopPeriod { + redLowAmpLight := redAmpSpeaker.BankedAmpNotes >= 1 + redHighAmpLight := redAmpSpeaker.BankedAmpNotes >= 2 + redCoopAmpLight := redAmpSpeaker.CoopActivated + if redAmplifiedTimeRemaining > 0 { + redAmplifiedTimePostWindow_ons = false + redLowAmpLight = int(redAmplifiedTimeRemaining*2)%2 == 0 + redHighAmpLight = !redLowAmpLight + arena.RealtimeScoreNotifier.Notify() + } + if !redAmplifiedTimePostWindow && !redAmplifiedTimePostWindow_ons{ + arena.RealtimeScoreNotifier.Notify() + redAmplifiedTimePostWindow_ons = true + } + + blueLowAmpLight := blueAmpSpeaker.BankedAmpNotes >= 1 + blueHighAmpLight := blueAmpSpeaker.BankedAmpNotes >= 2 + blueCoopAmpLight := blueAmpSpeaker.CoopActivated + if blueAmplifiedTimeRemaining > 0 { + blueAmplifiedTimePostWindow_ons = false + blueLowAmpLight = int(blueAmplifiedTimeRemaining*4)%2 == 0 + blueHighAmpLight = !blueLowAmpLight + arena.RealtimeScoreNotifier.Notify() + } + if !blueAmplifiedTimePostWindow && !blueAmplifiedTimePostWindow_ons{ + arena.RealtimeScoreNotifier.Notify() + blueAmplifiedTimePostWindow_ons = true + } + + arena.Plc.SetAmpLights( + redLowAmpLight, redHighAmpLight, redCoopAmpLight, blueLowAmpLight, blueHighAmpLight, blueCoopAmpLight, + ) + } else if arena.MatchState == PostMatch { + arena.Plc.SetAmpLights(false, false, false, false, false, false) } - blueLowAmpLight := blueAmpSpeaker.BankedAmpNotes >= 1 - blueHighAmpLight := blueAmpSpeaker.BankedAmpNotes >= 2 - blueCoopAmpLight := blueAmpSpeaker.CoopActivated - if blueAmplifiedTimeRemaining > 0 { - blueLowAmpLight = int(blueAmplifiedTimeRemaining*4)%2 == 0 - blueHighAmpLight = !blueLowAmpLight + // Handle the speaker outputs. + arena.Plc.SetSpeakerMotors( + arena.MatchState == AutoPeriod || arena.MatchState == PausePeriod || arena.MatchState == TeleopPeriod || + inGracePeriod, + ) + arena.Plc.SetSpeakerLights( + redAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, + blueAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, + ) + + // Handle the subwoofer outputs. + arena.Plc.SetSubwooferCountdown( + redAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, + blueAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, + ) + arena.Plc.SetPostMatchSubwooferLights(inGracePeriod) + + + return + }else{ + // Handle PLC functions that are always active. + if arena.Plc.GetFieldEStop() && !arena.matchAborted { + arena.AbortMatch() + } + redEStops, blueEStops := arena.Plc.GetTeamEStops() + redAStops, blueAStops := arena.Plc.GetTeamAStops() + arena.handleTeamStop("R1", redEStops[0], redAStops[0]) + arena.handleTeamStop("R2", redEStops[1], redAStops[1]) + arena.handleTeamStop("R3", redEStops[2], redAStops[2]) + arena.handleTeamStop("B1", blueEStops[0], blueAStops[0]) + arena.handleTeamStop("B2", blueEStops[1], blueAStops[1]) + arena.handleTeamStop("B3", blueEStops[2], blueAStops[2]) + redEthernets, blueEthernets := arena.Plc.GetEthernetConnected() + arena.AllianceStations["R1"].Ethernet = redEthernets[0] + arena.AllianceStations["R2"].Ethernet = redEthernets[1] + arena.AllianceStations["R3"].Ethernet = redEthernets[2] + arena.AllianceStations["B1"].Ethernet = blueEthernets[0] + arena.AllianceStations["B2"].Ethernet = blueEthernets[1] + arena.AllianceStations["B3"].Ethernet = blueEthernets[2] + + // Handle in-match PLC functions. + redScore := &arena.RedRealtimeScore.CurrentScore + oldRedScore := *redScore + blueScore := &arena.BlueRealtimeScore.CurrentScore + oldBlueScore := *blueScore + matchStartTime := arena.MatchStartTime + currentTime := time.Now() + teleopGracePeriod := matchStartTime.Add( + game.GetDurationToTeleopEnd() + game.SpeakerTeleopGracePeriodSec*time.Second, + ) + inGracePeriod := arena.MatchState == PostMatch && currentTime.Before(teleopGracePeriod) + + redAllianceReady := arena.checkAllianceStationsReady("R1", "R2", "R3") == nil + blueAllianceReady := arena.checkAllianceStationsReady("B1", "B2", "B3") == nil + + // Handle the evergreen PLC functions: stack lights, stack buzzer, and field reset light. + switch arena.MatchState { + case PreMatch: + if arena.lastMatchState != PreMatch { + arena.Plc.SetFieldResetLight(true) + } + fallthrough + case TimeoutActive: + fallthrough + case PostTimeout: + // Set the stack light state -- solid alliance color(s) if robots are not connected, solid orange if scores are + // not input, or blinking green if ready. + greenStackLight := redAllianceReady && blueAllianceReady && arena.Plc.GetCycleState(2, 0, 2) + arena.Plc.SetStackLights(!redAllianceReady, !blueAllianceReady, false, greenStackLight) + arena.Plc.SetStackBuzzer(redAllianceReady && blueAllianceReady) + + // Turn off lights if all teams become ready. + if redAllianceReady && blueAllianceReady { + arena.FieldReset = false + arena.Plc.SetFieldResetLight(false) + if arena.CurrentMatch.FieldReadyAt.IsZero() { + arena.CurrentMatch.FieldReadyAt = time.Now() + } + } + case PostMatch: + if arena.FieldReset { + arena.Plc.SetFieldResetLight(true) + } + scoreReady := arena.RedRealtimeScore.FoulsCommitted && arena.BlueRealtimeScore.FoulsCommitted && + arena.alliancePostMatchScoreReady("red") && arena.alliancePostMatchScoreReady("blue") + arena.Plc.SetStackLights(false, false, !scoreReady, false) + case AutoPeriod, PausePeriod, TeleopPeriod: + arena.Plc.SetStackBuzzer(false) + arena.Plc.SetStackLights(!redAllianceReady, !blueAllianceReady, false, true) } - arena.Plc.SetAmpLights( - redLowAmpLight, redHighAmpLight, redCoopAmpLight, blueLowAmpLight, blueHighAmpLight, blueCoopAmpLight, + // Get all the game-specific inputs and update the score. + redAmplifyButton, redCoopButton, blueAmplifyButton, blueCoopButton := arena.Plc.GetAmpButtons() + redAmpNoteCount, redSpeakerNoteCount, blueAmpNoteCount, blueSpeakerNoteCount := arena.Plc.GetAmpSpeakerNoteCounts() + redAmpSpeaker := &arena.RedRealtimeScore.CurrentScore.AmpSpeaker + blueAmpSpeaker := &arena.BlueRealtimeScore.CurrentScore.AmpSpeaker + redAmpSpeaker.UpdateState( + redAmpNoteCount, redSpeakerNoteCount, redAmplifyButton, redCoopButton, matchStartTime, currentTime, ) - } else if arena.MatchState == PostMatch { - arena.Plc.SetAmpLights(false, false, false, false, false, false) - } + blueAmpSpeaker.UpdateState( + blueAmpNoteCount, blueSpeakerNoteCount, blueAmplifyButton, blueCoopButton, matchStartTime, currentTime, + ) + if !oldRedScore.Equals(redScore) || !oldBlueScore.Equals(blueScore) { + arena.RealtimeScoreNotifier.Notify() + } - // Handle the speaker outputs. - arena.Plc.SetSpeakerMotors( - arena.MatchState == AutoPeriod || arena.MatchState == PausePeriod || arena.MatchState == TeleopPeriod || - inGracePeriod, - ) - arena.Plc.SetSpeakerLights( - redAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, - blueAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, - ) + // Handle the amp outputs. + redAmplifiedTimeRemaining := redAmpSpeaker.AmplifiedTimeRemaining(currentTime) + blueAmplifiedTimeRemaining := blueAmpSpeaker.AmplifiedTimeRemaining(currentTime) + if arena.MatchState == AutoPeriod || arena.MatchState == PausePeriod || arena.MatchState == TeleopPeriod { + redLowAmpLight := redAmpSpeaker.BankedAmpNotes >= 1 + redHighAmpLight := redAmpSpeaker.BankedAmpNotes >= 2 + redCoopAmpLight := redAmpSpeaker.CoopActivated + if redAmplifiedTimeRemaining > 0 { + redLowAmpLight = int(redAmplifiedTimeRemaining*2)%2 == 0 + redHighAmpLight = !redLowAmpLight + } - // Handle the subwoofer outputs. - arena.Plc.SetSubwooferCountdown( - redAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, - blueAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, - ) - arena.Plc.SetPostMatchSubwooferLights(inGracePeriod) + blueLowAmpLight := blueAmpSpeaker.BankedAmpNotes >= 1 + blueHighAmpLight := blueAmpSpeaker.BankedAmpNotes >= 2 + blueCoopAmpLight := blueAmpSpeaker.CoopActivated + if blueAmplifiedTimeRemaining > 0 { + blueLowAmpLight = int(blueAmplifiedTimeRemaining*4)%2 == 0 + blueHighAmpLight = !blueLowAmpLight + } + + arena.Plc.SetAmpLights( + redLowAmpLight, redHighAmpLight, redCoopAmpLight, blueLowAmpLight, blueHighAmpLight, blueCoopAmpLight, + ) + } else if arena.MatchState == PostMatch { + arena.Plc.SetAmpLights(false, false, false, false, false, false) + } + + // Handle the speaker outputs. + arena.Plc.SetSpeakerMotors( + arena.MatchState == AutoPeriod || arena.MatchState == PausePeriod || arena.MatchState == TeleopPeriod || + inGracePeriod, + ) + arena.Plc.SetSpeakerLights( + redAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, + blueAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, + ) + + // Handle the subwoofer outputs. + arena.Plc.SetSubwooferCountdown( + redAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, + blueAmplifiedTimeRemaining > 0 && arena.MatchState != PostMatch, + ) + arena.Plc.SetPostMatchSubwooferLights(inGracePeriod) + } } func (arena *Arena) handleTeamStop(station string, eStopState, aStopState bool) { diff --git a/field/arena_notifiers.go b/field/arena_notifiers.go index 8b4fc739..7975e68d 100644 --- a/field/arena_notifiers.go +++ b/field/arena_notifiers.go @@ -40,6 +40,7 @@ type audienceAllianceScoreFields struct { Score *game.Score ScoreSummary *game.ScoreSummary AmplifiedTimeRemainingSec int + AmplifiedTimePostWindow bool } // Instantiates notifiers and configures their message producing methods. @@ -333,6 +334,7 @@ func getAudienceAllianceScoreFields(allianceScore *RealtimeScore, fields.Score = &allianceScore.CurrentScore fields.ScoreSummary = allianceScoreSummary fields.AmplifiedTimeRemainingSec = allianceScore.AmplifiedTimeRemainingSec + fields.AmplifiedTimePostWindow = allianceScore.AmplifiedTimePostWindow return fields } diff --git a/field/realtime_score.go b/field/realtime_score.go index b1043c7f..2b857f7d 100644 --- a/field/realtime_score.go +++ b/field/realtime_score.go @@ -12,6 +12,7 @@ type RealtimeScore struct { Cards map[string]string FoulsCommitted bool AmplifiedTimeRemainingSec int + AmplifiedTimePostWindow bool } func NewRealtimeScore() *RealtimeScore { diff --git a/game/amp_speaker.go b/game/amp_speaker.go index 8d7aefe8..b8563bd1 100644 --- a/game/amp_speaker.go +++ b/game/amp_speaker.go @@ -49,7 +49,7 @@ func (ampSpeaker *AmpSpeaker) UpdateState( if currentTime.Before(teleopAmpValidityCutoff) { // Handle incoming Amp notes. ampSpeaker.TeleopAmpNotes += newAmpNotes - if !ampSpeaker.isAmplified(currentTime, false) { + if !ampSpeaker.IsAmplified(currentTime, false) { ampSpeaker.BankedAmpNotes = min(ampSpeaker.BankedAmpNotes+newAmpNotes, bankedAmpNoteLimit) } @@ -61,7 +61,7 @@ func (ampSpeaker *AmpSpeaker) UpdateState( } // Handle the amplify button. - if amplifyButton && !ampSpeaker.isAmplified(currentTime, false) && ampSpeaker.BankedAmpNotes >= 2 { + if amplifyButton && !ampSpeaker.IsAmplified(currentTime, false) && ampSpeaker.BankedAmpNotes >= 2 { ampSpeaker.LastAmplifiedTime = currentTime ampSpeaker.lastAmplifiedSpeakerNotes = 0 ampSpeaker.BankedAmpNotes -= 2 @@ -73,7 +73,7 @@ func (ampSpeaker *AmpSpeaker) UpdateState( GetDurationToTeleopEnd() + SpeakerTeleopGracePeriodSec*time.Second, ) if currentTime.Before(teleopSpeakerValidityCutoff) { - for newSpeakerNotes > 0 && ampSpeaker.isAmplified(currentTime, true) { + for newSpeakerNotes > 0 && ampSpeaker.IsAmplified(currentTime, true) { ampSpeaker.TeleopAmplifiedSpeakerNotes++ ampSpeaker.lastAmplifiedSpeakerNotes++ newSpeakerNotes-- @@ -84,7 +84,7 @@ func (ampSpeaker *AmpSpeaker) UpdateState( // Returns the amount of time remaining in the current amplification period, or zero if not currently amplified. func (ampSpeaker *AmpSpeaker) AmplifiedTimeRemaining(currentTime time.Time) float64 { - if !ampSpeaker.isAmplified(currentTime, false) { + if !ampSpeaker.IsAmplified(currentTime, false) { return 0 } return float64(AmplificationDurationSec) - currentTime.Sub(ampSpeaker.LastAmplifiedTime).Seconds() @@ -131,7 +131,7 @@ func (ampSpeaker *AmpSpeaker) speakerNotesScored() int { } // Returns whether the Speaker should be counting new incoming notes as amplified. -func (ampSpeaker *AmpSpeaker) isAmplified(currentTime time.Time, includeGracePeriod bool) bool { +func (ampSpeaker *AmpSpeaker) IsAmplified(currentTime time.Time, includeGracePeriod bool) bool { amplifiedValidityCutoff := ampSpeaker.LastAmplifiedTime.Add(time.Duration(AmplificationDurationSec) * time.Second) if includeGracePeriod { amplifiedValidityCutoff = amplifiedValidityCutoff.Add( diff --git a/static/js/scoring_panel.js b/static/js/scoring_panel.js index d47cffcb..c44a4f5b 100644 --- a/static/js/scoring_panel.js +++ b/static/js/scoring_panel.js @@ -79,12 +79,10 @@ const handleRealtimeScore = function(data) { $(`#coopertitionStatus>.value`).text(score.AmpSpeaker.CoopActivated ? "Cooperation Enabled" : "Cooperation"); $("#coopertitionStatus").attr("data-value", score.AmpSpeaker.CoopActivated); - $(`#amplificationActive>.value`).text(realtimeScore.Score.AmplifiedTimeRemainingSec > 0 ? "Amplification Active" : "Amplification"); - $("#amplificationActive").attr("data-value", data.Blue.AmplifiedTimeRemainingSec > 0); - //$("#amplificationActive").css("background-color", realtimeScore.AmplifiedTimeRemainingSec > 0 ? "yellow" : ""); - //$("#amplificationActive").css("color", !score.AmpAccumulatorDisable && score.AmplificationActive ? "black" : ""); - //$("#amplificationActive").css("background-color", !score.AmpAccumulatorDisable && score.AmplificationActive ? "yellow" : ""); - //$("#amplificationActive").css("color", !score.AmpAccumulatorDisable && score.AmplificationActive ? "black" : ""); + $(`#amplificationActive>.value`).text(realtimeScore.AmplifiedTimePostWindow ? "Amplification Active" : "Amplification"); + $("#amplificationActive").attr("data-value", realtimeScore.AmplifiedTimePostWindow); + $("#amplificationActive").css("background-color", !(realtimeScore.AmplifiedTimeRemainingSec > 0) && realtimeScore.AmplifiedTimePostWindow? "yellow" : ""); + $("#amplificationActive").css("color", !(realtimeScore.AmplifiedTimeRemainingSec > 0) && realtimeScore.AmplifiedTimePostWindow ? "black" : ""); }; // Handles an element click and sends the appropriate websocket message. diff --git a/web/setup_settings_test.go b/web/setup_settings_test.go index 4d2d87b0..48a9a485 100644 --- a/web/setup_settings_test.go +++ b/web/setup_settings_test.go @@ -45,7 +45,7 @@ func TestSetupSettingsDoubleElimination(t *testing.T) { recorder := web.postHttpResponse("/setup/settings", "playoffType=DoubleEliminationPlayoff&numPlayoffAlliances=3") assert.Equal(t, 303, recorder.Code) assert.Equal(t, model.DoubleEliminationPlayoff, web.arena.EventSettings.PlayoffType) - assert.Equal(t, 8, web.arena.EventSettings.NumPlayoffAlliances) + assert.Equal(t, 3, web.arena.EventSettings.NumPlayoffAlliances) } func TestSetupSettingsInvalidValues(t *testing.T) {