Update realtime scoring display and sounds for 2018.

This commit is contained in:
Patrick Fairbank
2018-07-21 18:27:53 -07:00
parent 0b9d6af240
commit 5f457f96ec
18 changed files with 384 additions and 444 deletions

View File

@@ -76,11 +76,11 @@ type Arena struct {
ScaleLeds led.Controller
RedSwitchLeds led.Controller
BlueSwitchLeds led.Controller
scale *game.Seesaw
redSwitch *game.Seesaw
blueSwitch *game.Seesaw
redVault *game.Vault
blueVault *game.Vault
Scale *game.Seesaw
RedSwitch *game.Seesaw
BlueSwitch *game.Seesaw
RedVault *game.Vault
BlueVault *game.Vault
}
type ArenaStatus struct {
@@ -226,17 +226,17 @@ func (arena *Arena) LoadMatch(match *model.Match) error {
arena.RedRealtimeScore = NewRealtimeScore()
arena.BlueRealtimeScore = NewRealtimeScore()
arena.FieldReset = false
arena.scale = new(game.Seesaw)
arena.redSwitch = new(game.Seesaw)
arena.blueSwitch = new(game.Seesaw)
arena.redVault = new(game.Vault)
arena.blueVault = new(game.Vault)
arena.Scale = &game.Seesaw{Kind: game.NeitherAlliance}
arena.RedSwitch = &game.Seesaw{Kind: game.RedAlliance}
arena.BlueSwitch = &game.Seesaw{Kind: game.BlueAlliance}
arena.RedVault = &game.Vault{Alliance: game.RedAlliance}
arena.BlueVault = &game.Vault{Alliance: game.BlueAlliance}
game.ResetPowerUps()
// Set a consistent initial value for field element sidedness.
arena.scale.SetSidedness(true)
arena.redSwitch.SetSidedness(true)
arena.blueSwitch.SetSidedness(true)
arena.Scale.SetSidedness(true)
arena.RedSwitch.SetSidedness(true)
arena.BlueSwitch.SetSidedness(true)
arena.ScaleLeds.SetSidedness(true)
arena.RedSwitchLeds.SetSidedness(true)
arena.BlueSwitchLeds.SetSidedness(true)
@@ -321,9 +321,9 @@ func (arena *Arena) StartMatch() error {
// Configure the field elements with the game-specific data.
switchNearIsRed := arena.CurrentMatch.GameSpecificData[0] == 'L'
scaleNearIsRed := arena.CurrentMatch.GameSpecificData[1] == 'L'
arena.scale.SetSidedness(scaleNearIsRed)
arena.redSwitch.SetSidedness(switchNearIsRed)
arena.blueSwitch.SetSidedness(switchNearIsRed)
arena.Scale.SetSidedness(scaleNearIsRed)
arena.RedSwitch.SetSidedness(switchNearIsRed)
arena.BlueSwitch.SetSidedness(switchNearIsRed)
arena.ScaleLeds.SetSidedness(scaleNearIsRed)
arena.RedSwitchLeds.SetSidedness(switchNearIsRed)
arena.BlueSwitchLeds.SetSidedness(switchNearIsRed)
@@ -701,35 +701,45 @@ func (arena *Arena) handlePlcInput() {
// Handle scale and switch ownership.
scale, redSwitch, blueSwitch := arena.Plc.GetScaleAndSwitches()
arena.scale.UpdateState(scale, currentTime)
arena.redSwitch.UpdateState(redSwitch, currentTime)
arena.blueSwitch.UpdateState(blueSwitch, currentTime)
arena.Scale.UpdateState(scale, currentTime)
arena.RedSwitch.UpdateState(redSwitch, currentTime)
arena.BlueSwitch.UpdateState(blueSwitch, currentTime)
if arena.MatchState == AutoPeriod {
redScore.AutoOwnershipPoints = 2 * int(arena.redSwitch.GetRedSeconds(matchStartTime, currentTime)+
arena.scale.GetRedSeconds(matchStartTime, currentTime))
blueScore.AutoOwnershipPoints = 2 * int(arena.blueSwitch.GetBlueSeconds(matchStartTime, currentTime)+
arena.scale.GetBlueSeconds(matchStartTime, currentTime))
redScore.AutoOwnershipPoints = 2 * int(arena.RedSwitch.GetRedSeconds(matchStartTime, currentTime)+
arena.Scale.GetRedSeconds(matchStartTime, currentTime))
blueScore.AutoOwnershipPoints = 2 * int(arena.BlueSwitch.GetBlueSeconds(matchStartTime, currentTime)+
arena.Scale.GetBlueSeconds(matchStartTime, currentTime))
} else {
redScore.TeleopOwnershipPoints = int(arena.redSwitch.GetRedSeconds(teleopStartTime, currentTime) +
arena.scale.GetRedSeconds(teleopStartTime, currentTime))
blueScore.TeleopOwnershipPoints = int(arena.blueSwitch.GetBlueSeconds(teleopStartTime, currentTime) +
arena.scale.GetBlueSeconds(teleopStartTime, currentTime))
redScore.TeleopOwnershipPoints = int(arena.RedSwitch.GetRedSeconds(teleopStartTime, currentTime) +
arena.Scale.GetRedSeconds(teleopStartTime, currentTime))
blueScore.TeleopOwnershipPoints = int(arena.BlueSwitch.GetBlueSeconds(teleopStartTime, currentTime) +
arena.Scale.GetBlueSeconds(teleopStartTime, currentTime))
}
// Handle vaults.
redForceDistance, redLevitateDistance, redBoostDistance, blueForceDistance, blueLevitateDistance, blueBoostDistance :=
arena.Plc.GetVaults()
arena.redVault.UpdateCubes(redForceDistance, redLevitateDistance, redBoostDistance)
arena.blueVault.UpdateCubes(blueForceDistance, blueLevitateDistance, blueBoostDistance)
arena.RedVault.UpdateCubes(redForceDistance, redLevitateDistance, redBoostDistance)
arena.BlueVault.UpdateCubes(blueForceDistance, blueLevitateDistance, blueBoostDistance)
redForce, redLevitate, redBoost, blueForce, blueLevitate, blueBoost := arena.Plc.GetPowerUpButtons()
arena.redVault.UpdateButtons(redForce, redLevitate, redBoost, currentTime)
arena.blueVault.UpdateButtons(blueForce, blueLevitate, blueBoost, currentTime)
redScore.ForceCubes, redScore.ForcePlayed = arena.redVault.ForceCubes, arena.redVault.ForcePowerUp != nil
redScore.LevitateCubes, redScore.LevitatePlayed = arena.redVault.LevitateCubes, arena.redVault.LevitatePlayed
redScore.BoostCubes, redScore.BoostPlayed = arena.redVault.BoostCubes, arena.redVault.BoostPowerUp != nil
blueScore.ForceCubes, blueScore.ForcePlayed = arena.blueVault.ForceCubes, arena.blueVault.ForcePowerUp != nil
blueScore.LevitateCubes, blueScore.LevitatePlayed = arena.blueVault.LevitateCubes, arena.blueVault.LevitatePlayed
blueScore.BoostCubes, blueScore.BoostPlayed = arena.blueVault.BoostCubes, arena.blueVault.BoostPowerUp != nil
arena.RedVault.UpdateButtons(redForce, redLevitate, redBoost, currentTime)
arena.BlueVault.UpdateButtons(blueForce, blueLevitate, blueBoost, currentTime)
redScore.ForceCubes, redScore.ForcePlayed = arena.RedVault.ForceCubes, arena.RedVault.ForcePowerUp != nil
redScore.LevitateCubes, redScore.LevitatePlayed = arena.RedVault.LevitateCubes, arena.RedVault.LevitatePlayed
redScore.BoostCubes, redScore.BoostPlayed = arena.RedVault.BoostCubes, arena.RedVault.BoostPowerUp != nil
blueScore.ForceCubes, blueScore.ForcePlayed = arena.BlueVault.ForceCubes, arena.BlueVault.ForcePowerUp != nil
blueScore.LevitateCubes, blueScore.LevitatePlayed = arena.BlueVault.LevitateCubes, arena.BlueVault.LevitatePlayed
blueScore.BoostCubes, blueScore.BoostPlayed = arena.BlueVault.BoostCubes, arena.BlueVault.BoostPowerUp != nil
// Check if a power up has been newly played and trigger the accompanying sound effect if so.
newRedPowerUp := arena.RedVault.CheckForNewlyPlayedPowerUp()
if newRedPowerUp != "" && !arena.MuteMatchSounds {
arena.PlaySoundNotifier.Notify("match-" + newRedPowerUp)
}
newBluePowerUp := arena.BlueVault.CheckForNewlyPlayedPowerUp()
if newBluePowerUp != "" && !arena.MuteMatchSounds {
arena.PlaySoundNotifier.Notify("match-" + newBluePowerUp)
}
if !oldRedScore.Equals(redScore) || !oldBlueScore.Equals(blueScore) {
arena.RealtimeScoreNotifier.Notify(nil)

View File

@@ -20,16 +20,17 @@ const (
)
// Power up state enum.
type state int
type PowerUpState int
const (
queued state = iota
active
expired
Unplayed PowerUpState = iota
Queued
Active
Expired
)
type PowerUp struct {
alliance
Alliance
effect
level int
startTime time.Time
@@ -41,14 +42,14 @@ func ResetPowerUps() {
powerUpUses = powerUpUses[:0]
}
func (powerUp *PowerUp) GetState(currentTime time.Time) state {
func (powerUp *PowerUp) GetState(currentTime time.Time) PowerUpState {
if powerUp.startTime.After(currentTime) {
return queued
return Queued
}
if powerUp.getEndTime().After(currentTime) {
return active
return Active
}
return expired
return Expired
}
func (powerUp *PowerUp) getEndTime() time.Time {
@@ -58,7 +59,7 @@ func (powerUp *PowerUp) getEndTime() time.Time {
// Returns the current active power up, or nil if there isn't one.
func getActivePowerUp(currentTime time.Time) *PowerUp {
for _, powerUp := range powerUpUses {
if powerUp.GetState(currentTime) == active {
if powerUp.GetState(currentTime) == Active {
return powerUp
}
}
@@ -75,10 +76,10 @@ func maybeActivatePowerUp(powerUp *PowerUp, currentTime time.Time) *PowerUp {
} else {
lastPowerUp := powerUpUses[len(powerUpUses)-1]
lastPowerUpState := lastPowerUp.GetState(currentTime)
if lastPowerUpState == expired {
if lastPowerUpState == Expired {
canActivate = true
powerUp.startTime = currentTime
} else if lastPowerUpState == active && lastPowerUp.alliance != powerUp.alliance {
} else if lastPowerUpState == Active && lastPowerUp.Alliance != powerUp.Alliance {
canActivate = true
powerUp.startTime = lastPowerUp.getEndTime()
}

View File

@@ -13,11 +13,11 @@ var matchStartTime = time.Unix(10, 0)
func TestPowerUpGetState(t *testing.T) {
powerUp := PowerUp{startTime: timeAfterStart(30)}
assert.Equal(t, queued, powerUp.GetState(timeAfterStart(25)))
assert.Equal(t, queued, powerUp.GetState(timeAfterStart(29.9)))
assert.Equal(t, active, powerUp.GetState(timeAfterStart(30.1)))
assert.Equal(t, active, powerUp.GetState(timeAfterStart(39.9)))
assert.Equal(t, expired, powerUp.GetState(timeAfterStart(40.1)))
assert.Equal(t, Queued, powerUp.GetState(timeAfterStart(25)))
assert.Equal(t, Queued, powerUp.GetState(timeAfterStart(29.9)))
assert.Equal(t, Active, powerUp.GetState(timeAfterStart(30.1)))
assert.Equal(t, Active, powerUp.GetState(timeAfterStart(39.9)))
assert.Equal(t, Expired, powerUp.GetState(timeAfterStart(40.1)))
}
func TestPowerUpActivate(t *testing.T) {
@@ -41,16 +41,21 @@ func TestPowerUpActivate(t *testing.T) {
}
func TestPowerUpQueue(t *testing.T) {
powerUp1 := &PowerUp{alliance: redAlliance}
maybeActivatePowerUp(powerUp1, timeAfterStart(60))
ResetPowerUps()
powerUp2 := &PowerUp{alliance: redAlliance}
powerUp1 := &PowerUp{Alliance: RedAlliance}
assert.NotNil(t, maybeActivatePowerUp(powerUp1, timeAfterStart(60)))
powerUp2 := &PowerUp{Alliance: RedAlliance}
assert.Nil(t, maybeActivatePowerUp(powerUp2, timeAfterStart(65)))
powerUp2.alliance = blueAlliance
powerUp2.Alliance = BlueAlliance
if assert.NotNil(t, maybeActivatePowerUp(powerUp2, timeAfterStart(65))) {
assert.Equal(t, timeAfterStart(70), powerUp2.startTime)
}
powerUp3 := &PowerUp{Alliance: RedAlliance}
assert.NotNil(t, maybeActivatePowerUp(powerUp3, timeAfterStart(81)))
assert.Equal(t, powerUp1, getActivePowerUp(timeAfterStart(69.9)))
assert.Equal(t, powerUp2, getActivePowerUp(timeAfterStart(70.1)))
}

View File

@@ -9,23 +9,23 @@ import (
"time"
)
type alliance int
type Alliance int
const (
neitherAlliance alliance = iota
redAlliance
blueAlliance
NeitherAlliance Alliance = iota
RedAlliance
BlueAlliance
)
type Seesaw struct {
kind alliance // Red or blue indicates that it is a switch; neither indicates the scale.
Kind Alliance // Red or blue indicates that it is a switch; neither indicates the scale.
nearIsRed bool
ownerships []*Ownership
}
type Ownership struct {
seesaw *Seesaw
ownedBy alliance
ownedBy Alliance
startTime time.Time
endTime *time.Time
}
@@ -38,46 +38,55 @@ func (seesaw *Seesaw) SetSidedness(nearIsRed bool) {
// Updates the internal timing state of the scale or switch given the current state of the sensors.
func (seesaw *Seesaw) UpdateState(state [2]bool, currentTime time.Time) {
ownedBy := neitherAlliance
ownedBy := NeitherAlliance
// Check if there is an active force power up for this seesaw.
currentPowerUp := getActivePowerUp(currentTime)
if currentPowerUp != nil && currentPowerUp.effect == force &&
(seesaw.kind == neitherAlliance && currentPowerUp.level >= 2 ||
(seesaw.kind == currentPowerUp.alliance && (currentPowerUp.level == 1 || currentPowerUp.level == 3))) {
ownedBy = currentPowerUp.alliance
(seesaw.Kind == NeitherAlliance && currentPowerUp.level >= 2 ||
(seesaw.Kind == currentPowerUp.Alliance && (currentPowerUp.level == 1 || currentPowerUp.level == 3))) {
ownedBy = currentPowerUp.Alliance
} else {
// Determine current ownership from sensor state.
if state[0] && !state[1] && seesaw.nearIsRed || state[1] && !state[0] && !seesaw.nearIsRed {
ownedBy = redAlliance
ownedBy = RedAlliance
} else if state[0] && !state[1] && !seesaw.nearIsRed || state[1] && !state[0] && seesaw.nearIsRed {
ownedBy = blueAlliance
ownedBy = BlueAlliance
}
}
// Update data if ownership has changed since last cycle.
currentOwnership := seesaw.getCurrentOwnership()
if currentOwnership != nil && ownedBy != currentOwnership.ownedBy ||
currentOwnership == nil && ownedBy != neitherAlliance {
currentOwnership == nil && ownedBy != NeitherAlliance {
if currentOwnership != nil {
currentOwnership.endTime = &currentTime
}
if ownedBy != neitherAlliance {
if ownedBy != NeitherAlliance {
newOwnership := &Ownership{seesaw: seesaw, ownedBy: ownedBy, startTime: currentTime}
seesaw.ownerships = append(seesaw.ownerships, newOwnership)
}
}
}
func (seesaw *Seesaw) GetOwnedBy() Alliance {
ownership := seesaw.getCurrentOwnership()
if ownership == nil {
return NeitherAlliance
} else {
return ownership.ownedBy
}
}
// Returns the auto and teleop period scores for the red alliance.
func (seesaw *Seesaw) GetRedSeconds(startTime, endTime time.Time) float64 {
return seesaw.getAllianceSeconds(redAlliance, startTime, endTime)
return seesaw.getAllianceSeconds(RedAlliance, startTime, endTime)
}
// Returns the auto and teleop period scores for the blue alliance.
func (seesaw *Seesaw) GetBlueSeconds(startTime, endTime time.Time) float64 {
return seesaw.getAllianceSeconds(blueAlliance, startTime, endTime)
return seesaw.getAllianceSeconds(BlueAlliance, startTime, endTime)
}
func (seesaw *Seesaw) getCurrentOwnership() *Ownership {
@@ -90,7 +99,7 @@ func (seesaw *Seesaw) getCurrentOwnership() *Ownership {
return nil
}
func (seesaw *Seesaw) getAllianceSeconds(ownedBy alliance, startTime, endTime time.Time) float64 {
func (seesaw *Seesaw) getAllianceSeconds(ownedBy Alliance, startTime, endTime time.Time) float64 {
var seconds float64
for _, ownership := range seesaw.ownerships {
if ownership.ownedBy == ownedBy {
@@ -122,9 +131,9 @@ func (ownership *Ownership) getSeconds(startTime, endTime time.Time, ignoreBoost
// Find the boost power up applicable to this seesaw and alliance, if it exists.
var boostPowerUp *PowerUp
for _, powerUp := range powerUpUses {
if powerUp.effect == boost && ownership.ownedBy == powerUp.alliance {
if ownership.seesaw.kind == neitherAlliance && powerUp.level >= 2 ||
ownership.seesaw.kind != neitherAlliance && (powerUp.level == 1 || powerUp.level == 3) {
if powerUp.effect == boost && ownership.ownedBy == powerUp.Alliance {
if ownership.seesaw.Kind == NeitherAlliance && powerUp.level >= 2 ||
ownership.seesaw.Kind != NeitherAlliance && (powerUp.level == 1 || powerUp.level == 3) {
boostPowerUp = powerUp
break
}

View File

@@ -9,7 +9,7 @@ import (
)
func TestOwnership(t *testing.T) {
ownership := Ownership{nil, redAlliance, timeAfterStart(1), nil}
ownership := Ownership{nil, RedAlliance, timeAfterStart(1), nil}
assert.Equal(t, 0.0, ownership.getSeconds(timeAfterStart(0), timeAfterStart(0), true))
assert.Equal(t, 0.5, ownership.getSeconds(timeAfterStart(0), timeAfterStart(1.5), true))
assert.Equal(t, 8.75, ownership.getSeconds(timeAfterStart(0), timeAfterStart(9.75), true))
@@ -31,7 +31,7 @@ func TestOwnership(t *testing.T) {
func TestSecondCounting(t *testing.T) {
ResetPowerUps()
redSwitch := &Seesaw{kind: redAlliance}
redSwitch := &Seesaw{Kind: RedAlliance}
redSwitch.SetSidedness(true)
// Test that there is no accumulation before the start of the match.
@@ -69,15 +69,15 @@ func TestSecondCounting(t *testing.T) {
func TestForce(t *testing.T) {
ResetPowerUps()
blueSwitch := &Seesaw{kind: blueAlliance}
blueSwitch := &Seesaw{Kind: BlueAlliance}
blueSwitch.SetSidedness(true)
scale := &Seesaw{kind: neitherAlliance}
scale := &Seesaw{Kind: NeitherAlliance}
scale.SetSidedness(true)
// Force switch only.
blueSwitch.UpdateState([2]bool{true, false}, timeAfterStart(0))
scale.UpdateState([2]bool{true, false}, timeAfterStart(0))
powerUp := &PowerUp{alliance: blueAlliance, effect: force, level: 1}
powerUp := &PowerUp{Alliance: BlueAlliance, effect: force, level: 1}
maybeActivatePowerUp(powerUp, timeAfterStart(2.5))
blueSwitch.UpdateState([2]bool{true, false}, timeAfterStart(2.5))
scale.UpdateState([2]bool{true, false}, timeAfterStart(2.5))
@@ -91,7 +91,7 @@ func TestForce(t *testing.T) {
assert.Equal(t, 0.0, scale.GetBlueSeconds(timeAfterStart(0), timeAfterStart(15)))
// Force scale only.
powerUp = &PowerUp{alliance: blueAlliance, effect: force, level: 2}
powerUp = &PowerUp{Alliance: BlueAlliance, effect: force, level: 2}
maybeActivatePowerUp(powerUp, timeAfterStart(20))
blueSwitch.UpdateState([2]bool{true, false}, timeAfterStart(20))
scale.UpdateState([2]bool{true, false}, timeAfterStart(20))
@@ -101,7 +101,7 @@ func TestForce(t *testing.T) {
assert.Equal(t, 10.0, scale.GetBlueSeconds(timeAfterStart(20), timeAfterStart(40)))
// Force both switch and scale.
powerUp = &PowerUp{alliance: blueAlliance, effect: force, level: 3}
powerUp = &PowerUp{Alliance: BlueAlliance, effect: force, level: 3}
maybeActivatePowerUp(powerUp, timeAfterStart(50))
blueSwitch.UpdateState([2]bool{true, false}, timeAfterStart(50))
scale.UpdateState([2]bool{true, false}, timeAfterStart(50))
@@ -114,15 +114,15 @@ func TestForce(t *testing.T) {
func TestBoost(t *testing.T) {
ResetPowerUps()
blueSwitch := &Seesaw{kind: blueAlliance}
blueSwitch := &Seesaw{Kind: BlueAlliance}
blueSwitch.SetSidedness(true)
scale := &Seesaw{kind: neitherAlliance}
scale := &Seesaw{Kind: NeitherAlliance}
scale.SetSidedness(false)
// Test within continuous ownership period.
blueSwitch.UpdateState([2]bool{false, true}, timeAfterStart(20))
scale.UpdateState([2]bool{true, false}, timeAfterStart(20))
powerUp := &PowerUp{alliance: blueAlliance, effect: boost, level: 2}
powerUp := &PowerUp{Alliance: BlueAlliance, effect: boost, level: 2}
maybeActivatePowerUp(powerUp, timeAfterStart(25))
assert.Equal(t, 5.0, scale.GetBlueSeconds(timeAfterStart(0), timeAfterStart(25)))
assert.Equal(t, 6.0, scale.GetBlueSeconds(timeAfterStart(0), timeAfterStart(25.5)))
@@ -136,7 +136,7 @@ func TestBoost(t *testing.T) {
ResetPowerUps()
blueSwitch.UpdateState([2]bool{false, false}, timeAfterStart(44))
scale.UpdateState([2]bool{false, false}, timeAfterStart(44))
powerUp = &PowerUp{alliance: blueAlliance, effect: boost, level: 3}
powerUp = &PowerUp{Alliance: BlueAlliance, effect: boost, level: 3}
maybeActivatePowerUp(powerUp, timeAfterStart(45))
assert.Equal(t, 0.0, blueSwitch.GetBlueSeconds(timeAfterStart(45), timeAfterStart(50)))
assert.Equal(t, 0.0, scale.GetBlueSeconds(timeAfterStart(45), timeAfterStart(50)))
@@ -151,7 +151,7 @@ func TestBoost(t *testing.T) {
ResetPowerUps()
scale.UpdateState([2]bool{false, true}, timeAfterStart(65))
assert.Equal(t, 5.0, scale.GetRedSeconds(timeAfterStart(65), timeAfterStart(70)))
powerUp = &PowerUp{alliance: redAlliance, effect: boost, level: 2}
powerUp = &PowerUp{Alliance: RedAlliance, effect: boost, level: 2}
maybeActivatePowerUp(powerUp, timeAfterStart(70))
scale.UpdateState([2]bool{false, false}, timeAfterStart(72.5))
assert.Equal(t, 10.0, scale.GetRedSeconds(timeAfterStart(65), timeAfterStart(72.5)))
@@ -163,7 +163,7 @@ func TestBoost(t *testing.T) {
// Test with just the switch.
blueSwitch.UpdateState([2]bool{false, true}, timeAfterStart(100))
scale.UpdateState([2]bool{true, false}, timeAfterStart(100))
powerUp = &PowerUp{alliance: blueAlliance, effect: boost, level: 1}
powerUp = &PowerUp{Alliance: BlueAlliance, effect: boost, level: 1}
maybeActivatePowerUp(powerUp, timeAfterStart(100))
assert.Equal(t, 20.0, blueSwitch.GetBlueSeconds(timeAfterStart(100), timeAfterStart(110)))
assert.Equal(t, 10.0, scale.GetBlueSeconds(timeAfterStart(100), timeAfterStart(110)))

View File

@@ -10,13 +10,14 @@ import (
)
type Vault struct {
alliance alliance
ForceCubes int
LevitateCubes int
BoostCubes int
LevitatePlayed bool
ForcePowerUp *PowerUp
BoostPowerUp *PowerUp
Alliance
ForceCubes int
LevitateCubes int
BoostCubes int
LevitatePlayed bool
ForcePowerUp *PowerUp
BoostPowerUp *PowerUp
newlyPlayedPowerUp string
}
// Updates the state of the vault given the state of the individual power cube sensors.
@@ -30,19 +31,33 @@ func (vault *Vault) UpdateCubes(forceDistance, levitateDistance, boostDistance u
func (vault *Vault) UpdateButtons(forceButton, levitateButton, boostButton bool, currentTime time.Time) {
if levitateButton && vault.LevitateCubes == 3 && !vault.LevitatePlayed {
vault.LevitatePlayed = true
vault.newlyPlayedPowerUp = "levitate"
}
if forceButton && vault.ForceCubes > 0 && vault.ForcePowerUp == nil {
vault.ForcePowerUp = maybeActivatePowerUp(&PowerUp{effect: force, alliance: vault.alliance,
vault.ForcePowerUp = maybeActivatePowerUp(&PowerUp{effect: force, Alliance: vault.Alliance,
level: vault.ForceCubes}, currentTime)
if vault.ForcePowerUp != nil {
vault.newlyPlayedPowerUp = "force"
}
}
if boostButton && vault.BoostCubes > 0 && vault.BoostPowerUp == nil {
vault.BoostPowerUp = maybeActivatePowerUp(&PowerUp{effect: boost, alliance: vault.alliance,
vault.BoostPowerUp = maybeActivatePowerUp(&PowerUp{effect: boost, Alliance: vault.Alliance,
level: vault.BoostCubes}, currentTime)
if vault.BoostPowerUp != nil {
vault.newlyPlayedPowerUp = "boost"
}
}
}
// Returns the name of the newly-played power up if there is one, or an empty string otherwise, and resets the state.
func (vault *Vault) CheckForNewlyPlayedPowerUp() string {
powerUp := vault.newlyPlayedPowerUp
vault.newlyPlayedPowerUp = ""
return powerUp
}
func countCubes(distance uint16) int {
// TODO(patrick): Update with real values once there is a physical setup to test with.
if distance >= 3000 {

View File

@@ -71,7 +71,7 @@ func TestVaultLevitate(t *testing.T) {
}
func TestVaultForce(t *testing.T) {
vault := Vault{alliance: blueAlliance}
vault := Vault{Alliance: BlueAlliance}
ResetPowerUps()
vault.UpdateCubes(0, 0, 0)
@@ -86,30 +86,30 @@ func TestVaultForce(t *testing.T) {
vault.UpdateCubes(1000, 0, 0)
vault.UpdateButtons(true, false, false, time.Now())
if assert.NotNil(t, vault.ForcePowerUp) {
assert.Equal(t, blueAlliance, vault.ForcePowerUp.alliance)
assert.Equal(t, BlueAlliance, vault.ForcePowerUp.Alliance)
assert.Equal(t, force, vault.ForcePowerUp.effect)
assert.Equal(t, 1, vault.ForcePowerUp.level)
}
// Activation with two cubes.
vault = Vault{alliance: redAlliance}
vault = Vault{Alliance: RedAlliance}
ResetPowerUps()
vault.UpdateCubes(2000, 0, 0)
vault.UpdateButtons(true, false, false, time.Now())
if assert.NotNil(t, vault.ForcePowerUp) {
assert.Equal(t, redAlliance, vault.ForcePowerUp.alliance)
assert.Equal(t, RedAlliance, vault.ForcePowerUp.Alliance)
assert.Equal(t, force, vault.ForcePowerUp.effect)
assert.Equal(t, 2, vault.ForcePowerUp.level)
}
// Activation with three cubes.
vault = Vault{alliance: blueAlliance}
vault = Vault{Alliance: BlueAlliance}
ResetPowerUps()
vault.UpdateCubes(3000, 0, 0)
vault.UpdateButtons(true, false, false, time.Now())
assert.NotNil(t, vault.ForcePowerUp)
if assert.NotNil(t, vault.ForcePowerUp) {
assert.Equal(t, blueAlliance, vault.ForcePowerUp.alliance)
assert.Equal(t, BlueAlliance, vault.ForcePowerUp.Alliance)
assert.Equal(t, force, vault.ForcePowerUp.effect)
assert.Equal(t, 3, vault.ForcePowerUp.level)
}
@@ -120,7 +120,7 @@ func TestVaultForce(t *testing.T) {
}
func TestVaultBoost(t *testing.T) {
vault := Vault{alliance: blueAlliance}
vault := Vault{Alliance: BlueAlliance}
ResetPowerUps()
vault.UpdateCubes(0, 0, 0)
@@ -135,30 +135,30 @@ func TestVaultBoost(t *testing.T) {
vault.UpdateCubes(0, 0, 1000)
vault.UpdateButtons(false, false, true, time.Now())
if assert.NotNil(t, vault.BoostPowerUp) {
assert.Equal(t, blueAlliance, vault.BoostPowerUp.alliance)
assert.Equal(t, BlueAlliance, vault.BoostPowerUp.Alliance)
assert.Equal(t, boost, vault.BoostPowerUp.effect)
assert.Equal(t, 1, vault.BoostPowerUp.level)
}
// Activation with two cubes.
vault = Vault{alliance: redAlliance}
vault = Vault{Alliance: RedAlliance}
ResetPowerUps()
vault.UpdateCubes(0, 0, 2000)
vault.UpdateButtons(false, false, true, time.Now())
if assert.NotNil(t, vault.BoostPowerUp) {
assert.Equal(t, redAlliance, vault.BoostPowerUp.alliance)
assert.Equal(t, RedAlliance, vault.BoostPowerUp.Alliance)
assert.Equal(t, boost, vault.BoostPowerUp.effect)
assert.Equal(t, 2, vault.BoostPowerUp.level)
}
// Activation with three cubes.
vault = Vault{alliance: blueAlliance}
vault = Vault{Alliance: BlueAlliance}
ResetPowerUps()
vault.UpdateCubes(0, 0, 3000)
vault.UpdateButtons(false, false, true, time.Now())
assert.NotNil(t, vault.BoostPowerUp)
if assert.NotNil(t, vault.BoostPowerUp) {
assert.Equal(t, blueAlliance, vault.BoostPowerUp.alliance)
assert.Equal(t, BlueAlliance, vault.BoostPowerUp.Alliance)
assert.Equal(t, boost, vault.BoostPowerUp.effect)
assert.Equal(t, 3, vault.BoostPowerUp.level)
}
@@ -167,3 +167,44 @@ func TestVaultBoost(t *testing.T) {
vault.UpdateButtons(false, false, false, time.Now())
assert.NotNil(t, vault.BoostPowerUp)
}
func TestVaultMultipleActivations(t *testing.T) {
redVault := Vault{Alliance: RedAlliance}
redVault.UpdateCubes(1000, 3000, 1000)
blueVault := Vault{Alliance: BlueAlliance}
blueVault.UpdateCubes(1000, 3000, 1000)
ResetPowerUps()
redVault.UpdateButtons(true, false, false, timeAfterStart(0))
redVault.UpdateButtons(false, false, false, timeAfterStart(1))
if assert.NotNil(t, redVault.ForcePowerUp) {
assert.Equal(t, Active, redVault.ForcePowerUp.GetState(timeAfterStart(0.5)))
}
assert.Equal(t, "force", redVault.CheckForNewlyPlayedPowerUp())
assert.Equal(t, "", redVault.CheckForNewlyPlayedPowerUp())
redVault.UpdateButtons(false, true, false, timeAfterStart(2))
redVault.UpdateButtons(false, false, false, timeAfterStart(3))
assert.True(t, redVault.LevitatePlayed)
assert.Equal(t, "levitate", redVault.CheckForNewlyPlayedPowerUp())
assert.Equal(t, "", redVault.CheckForNewlyPlayedPowerUp())
blueVault.UpdateButtons(false, false, true, timeAfterStart(4))
blueVault.UpdateButtons(false, false, false, timeAfterStart(5))
if assert.NotNil(t, blueVault.BoostPowerUp) {
assert.Equal(t, Queued, blueVault.BoostPowerUp.GetState(timeAfterStart(4.5)))
}
assert.Equal(t, "boost", blueVault.CheckForNewlyPlayedPowerUp())
assert.Equal(t, "", blueVault.CheckForNewlyPlayedPowerUp())
assert.Equal(t, Expired, redVault.ForcePowerUp.GetState(timeAfterStart(11)))
assert.Equal(t, Active, blueVault.BoostPowerUp.GetState(timeAfterStart(11)))
assert.Equal(t, Expired, blueVault.BoostPowerUp.GetState(timeAfterStart(21)))
redVault.UpdateButtons(false, false, true, timeAfterStart(25))
redVault.UpdateButtons(false, false, false, timeAfterStart(26))
if assert.NotNil(t, redVault.BoostPowerUp) {
assert.Equal(t, Active, redVault.BoostPowerUp.GetState(timeAfterStart(25.5)))
}
assert.Equal(t, "boost", redVault.CheckForNewlyPlayedPowerUp())
assert.Equal(t, "", redVault.CheckForNewlyPlayedPowerUp())
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -104,37 +104,92 @@ html {
color: #fff;
opacity: 0;
}
.score-fields-icons {
line-height: 99px;
text-align: center;
width: 30px;
}
.score-fields-icons span {
display: inline-block;
line-height: 33px;
}
.score-fields-text {
width: 19px;
}
.score-fields-text span {
.score-fields span {
display: inline-block;
line-height: 34px;
padding: 0;
}
.power-up[data-state="0"] {
opacity: 1;
}
.power-up[data-state="1"] {
color: #ffff00;
}
.power-up[data-state="2"] {
color: #ffff00;
animation: power-up-blinker 0.5s linear infinite;
}
.power-up[data-state="3"] {
opacity: 0.4;
}
@keyframes power-up-blinker {
50% {
opacity: 0.5;
}
}
.score-fields-icons {
text-align: center;
width: 28px;
}
.score-fields-text {
width: 19px;
}
.powerup-progress {
float: left;
height: 100%;
margin: 0 4px 0 4px;
width: 6px;
}
.powerup-progress>div {
position: absolute;
top: 0;
bottom: 0;
width: 6px;
height: 0;
margin: auto;
background-color: #fff;
opacity: 0.7;
border-radius: 3px;
}
#logo {
position: relative;
top: 30px;
height: 85px;
top: 35px;
height: 75px;
}
#matchTime {
position: relative;
top: 6px;
top: 4px;
height: 60px;
color: #222;
font-family: "FuturaLTBold";
font-size: 32px;
opacity: 0;
}
.seesaw-indicator {
position: absolute;
bottom: 8px;
border-radius: 3px;
width: 11px;
height: 16px;
background-color: #ccc;
border: 1px solid #333;
opacity: 0;
}
.seesaw-indicator[data-owned-by="1"] {
background-color: #ff4444;
}
.seesaw-indicator[data-owned-by="2"] {
background-color: #2080ff;
}
#redSwitchIndicator {
left: 50px;
}
#scaleIndicator {
left: 68px;
}
#blueSwitchIndicator {
left: 86px;
}
#blindsContainer {
position: fixed;
top: 0;
@@ -406,11 +461,3 @@ html {
font-family: "FuturaLTBold";
line-height: 87px;
}
.score-icon {
position: relative;
top: -4px;
height: 23px;
}
.score-icon-right {
-webkit-transform: scaleX(-1);
}

View File

@@ -1,85 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="-4 6 90 90" style="enable-background:new -4 6 90 90;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:none;stroke:#000000;stroke-width:18;stroke-miterlimit:10;}
</style>
<g id="XMLID_40_">
<path id="XMLID_61_" d="M11.9,202.7c-1.1-0.2-2.2-0.7-3.1-1.5c-0.5-0.5-1.1-1.2-1.6-1.8c-0.7-0.9-1-2.2-0.8-3.4
c0.2-0.8,0.3-1.6,0.6-2.5c0.4-1.1,0.8-2.1,1.2-3.1l0.1-0.2c0.2-0.5,0.4-1,0.7-1.6l0.4-0.9l0.6-1.3c0.5-1.1,1-2.2,1.5-3.4
c0.6-1.4,1.3-2.7,1.9-4.1c1.2-2.5,2.4-5,3.7-7.4c0.8-1.6,1.5-2.9,2.2-4c0.9-1.5,1.8-3,2.9-4.6c0.5-0.8,1.1-1.6,1.6-2.3
c0.2-0.2,0.4-0.5,0.5-0.7c0-0.1,0-0.2-0.1-0.2c-0.2-0.7-0.4-1.7-0.3-2.9c0-0.1,0.1-0.5,0.1-0.5s-0.1-0.2-0.4-0.5
c-0.5-0.5-1-1-1.5-1.5c-0.6-0.6-1.2-1.2-1.8-1.9c-1.4-1.7-2.9-3.3-4.2-5c-1.5-2.1-3-4.2-4.4-6.2l-0.3-0.5c-1-1.4-1.8-2.8-2.8-4.4
c-1-1.7-2-3.3-3-5s-1.7-3.1-2.4-4.5c-0.6-1.4-1.3-3-1.6-4.9c-0.4-3.3,1.4-5.8,4.6-6.6c0.5-0.1,1-0.2,1.5-0.3h0.1
c0.4-0.1,0.9-0.1,1.3,0c1.6,0.2,2.5,1.3,2.8,1.6l0.5,0.5c0.9,0.9,1.8,1.9,2.6,3c1.9,2.4,3.8,5,5.6,7.6c1.6,2.2,3.2,4.6,5,7.3
c1.3,1.9,2.6,4,4,6.4c1.2,1.9,2.3,4,3.2,6.2c0.2,0.6,0.5,1.2,0.8,1.8l0,0c1.2,0.3,2.3,0.8,3.2,1.6l0,0c0.8-0.1,1.6-0.3,2.5-0.5
c2.2-0.6,4.5-1.2,6.9-1.5s5.2-0.6,8.1-0.8c2.5-0.2,5-0.3,7.4-0.4c2.2-0.1,4.2-0.1,6.1-0.1s4.1,0,6.3,0.4c0.7,0.1,1.3,0.2,2,0.4
c1.2,0.3,2.9,0.8,4.2,2.4c1.1,1.3,1.4,3,0.9,4.7c-0.2,0.7-0.4,1.3-0.6,1.9l-0.1,0.3c-0.4,1-1.2,2.3-3.3,2.8l-0.5,0.1
c-1,0.3-2.1,0.5-3.3,0.7c-3.9,0.5-7.1,0.9-10.1,1.2s-6.1,0.5-8.8,0.7c-2.1,0.1-4.3,0.2-6.6,0.3c-3.1,0.1-6-0.1-8.8-0.4
c-0.5-0.1-0.9-0.1-1.4-0.1c-0.1,0.1-0.1,0.1-0.2,0.2c-0.8,0.9-1.7,1.5-2.8,1.9c0,0,0,0,0,0.1c-0.2,0.4-0.4,1-0.6,1.6l-0.2,0.6
c-0.1,0.4-0.2,0.8-0.4,1.2c-0.3,1.1-0.6,2.2-1,3.3c-0.6,1.7-1.3,3.4-2,5c-1,2.3-2.1,4.7-3.4,7.2c-0.9,1.8-1.8,3.5-2.7,5.2l-0.2,0.3
c-0.7,1.3-1.4,2.7-2.3,4.1c-1.3,2.2-2.7,4.4-4.5,6.4c-0.7,0.7-1.4,1.2-2,1.6l-0.1,0.1C14.6,202.6,13.3,202.9,11.9,202.7z"/>
<path id="XMLID_513_" d="M12.5,188.9c0.6-1.3,1.3-2.9,2-4.6c0.6-1.3,1.2-2.7,1.9-4c1.2-2.5,2.4-4.9,3.6-7.4
c0.6-1.3,1.3-2.6,2.1-3.8c0.9-1.5,1.8-3,2.8-4.4c0.8-1.1,1.6-2.2,2.4-3.3c0.5-0.7,0.5-1.4,0.3-2.2c-0.1-0.7-0.4-1.4-0.3-2.1
c0-0.3,0.1-0.7,0.1-1c0-1.1-0.6-2-1.3-2.8c-1-1.2-2.2-2.2-3.2-3.4c-1.4-1.6-2.7-3.1-4-4.8c-1.6-2.1-3.1-4.4-4.6-6.6
c-0.9-1.4-1.8-2.8-2.7-4.2c-1-1.6-2-3.2-2.9-4.9c-0.8-1.4-1.6-2.8-2.2-4.2c-0.6-1.2-1.1-2.5-1.3-3.8c-0.2-1.5,0.4-2.4,2-2.8
c0.4-0.1,0.9-0.2,1.3-0.2c0.5-0.1,0.8,0.2,1.1,0.5c1,1.1,2,2.1,2.9,3.3c1.9,2.5,3.8,5,5.6,7.5c1.7,2.4,3.3,4.8,4.9,7.2
c1.4,2.1,2.7,4.1,3.9,6.2c1.1,1.9,2.1,3.8,2.9,5.8c0.3,0.8,0.7,1.6,1.1,2.3c0.4,0.9,1.2,1.3,2.1,1.5c0.7,0.2,1.4,0.5,1.9,1
c0.7,0.7,1.6,0.8,2.5,0.7c1-0.1,2-0.3,2.9-0.6c2.1-0.6,4.2-1.1,6.4-1.4c2.7-0.3,5.3-0.6,8-0.8c2.4-0.2,4.9-0.3,7.3-0.4
c2-0.1,4-0.1,5.9-0.1c2.5,0,5,0.1,7.5,0.7c0.9,0.2,1.7,0.5,2.3,1.2c0.4,0.5,0.5,1,0.3,1.6s-0.4,1.3-0.6,1.9
c-0.2,0.4-0.5,0.6-0.9,0.7c-1.1,0.3-2.3,0.6-3.4,0.7c-3.3,0.4-6.7,0.8-10,1.2c-2.9,0.3-5.8,0.5-8.6,0.7c-2.1,0.1-4.3,0.2-6.5,0.3
c-2.8,0.1-5.5,0-8.3-0.4c-0.8-0.1-1.6-0.1-2.4-0.1c-0.6,0-1.1,0.4-1.6,0.8c-0.2,0.2-0.4,0.4-0.6,0.6c-0.4,0.5-1,0.8-1.6,1
c-0.8,0.2-1.3,0.8-1.7,1.5c-0.6,0.9-0.8,2-1.1,3c-0.4,1.5-0.8,3-1.3,4.4c-0.6,1.6-1.2,3.2-1.9,4.8c-1.1,2.4-2.2,4.8-3.3,7.1
c-0.9,1.8-1.9,3.6-2.8,5.4c-0.7,1.3-1.4,2.6-2.2,3.9c-1.2,2-2.5,4.1-4.1,5.9c-0.5,0.5-1,0.9-1.6,1.3c-0.7,0.5-1.7,0.4-2.4-0.3
c-0.5-0.5-0.9-1-1.3-1.5c-0.1-0.2-0.2-0.5-0.1-0.7c0.1-0.7,0.3-1.4,0.5-2.1c0.3-1.1,0.8-2.1,1.2-3.1
C11.8,190.6,12.1,189.9,12.5,188.9z"/>
</g>
<g id="XMLID_30_">
<g id="XMLID_28_">
<path id="XMLID_42_" d="M-324.1,52.7c-2.8,0-3.4-1.6-1.5-3.6l38.4-40.2c1.9-2,5-2,6.9,0l38.4,40.2c1.9,2,1.2,3.6-1.5,3.6H-324.1z"
/>
</g>
<g id="XMLID_29_">
<path id="XMLID_69_" d="M-264.7,93.7c0,1.6-1.3,3-3,3h-32.2c-1.7,0-3-1.4-3-3v-61c0-1.6,1.3-3,3-3h32.2c1.7,0,3,1.4,3,3V93.7z"/>
</g>
</g>
<path class="st0" d="M41,12C19.8,12,2.7,29.1,2.7,50.3c0,21.2,17.1,38.3,38.3,38.3s38.3-17.1,38.3-38.3C79.3,29.1,62.2,12,41,12z
M37.8,16.5c4.6-0.1,8.4,1.6,8.5,3.8c0,2.2-3.7,4-8.3,4c-4.6,0.1-8.4-1.6-8.5-3.8S33.2,16.6,37.8,16.5z M20.9,46.2
c-0.6,4.5-3.7,7.9-7.1,7.5c-3.3-0.4-5.6-4.4-5-9c0.6-4.5,3.7-7.9,7.1-7.5C19.2,37.7,21.4,41.7,20.9,46.2z M45.2,75.3
c-0.4,3.2-4.4,5.5-9,4.9c-4.6-0.5-8.1-3.5-7.7-6.8c0.4-3.2,4.4-5.5,9-4.9C42.2,69,45.6,72.1,45.2,75.3z M54.4,50.3
c-0.9,4.5-5.3,7.4-9.8,6.5c-4.5-0.9-7.4-5.3-6.5-9.8c0.9-4.5,5.3-7.4,9.8-6.5C52.4,41.5,55.3,45.8,54.4,50.3z M72.4,54.7
c-2,0.3-4.1-3.1-4.8-7.7c-0.7-4.5,0.3-8.4,2.3-8.8c2-0.3,4.1,3.1,4.8,7.7C75.4,50.5,74.3,54.4,72.4,54.7z"/>
<g id="XMLID_15_">
<g id="XMLID_3_">
<polygon id="XMLID_20_" points="13.1,303.3 3.7,299.4 34.2,227.8 43.5,231.7 "/>
</g>
<g id="XMLID_4_">
<polygon id="XMLID_19_" points="49.4,303.3 40,299.4 70.5,227.8 79.8,231.7 "/>
</g>
<g id="XMLID_5_">
<rect id="XMLID_18_" x="14.2" y="282.8" width="36.4" height="10"/>
</g>
<g id="XMLID_6_">
<rect id="XMLID_17_" x="24.3" y="261.4" width="36.4" height="10"/>
</g>
<g id="XMLID_7_">
<rect id="XMLID_16_" x="32.3" y="240" width="36.4" height="10"/>
</g>
</g>
<g id="XMLID_21_">
<ellipse id="XMLID_8_" transform="matrix(0.3511 -0.9363 0.9363 0.3511 -466.2337 -55.1614)" cx="-272.9" cy="308.8" rx="26.1" ry="26.8"/>
<ellipse id="XMLID_9_" transform="matrix(0.3511 -0.9363 0.9363 0.3511 -495.1177 -46.7863)" cx="-281.3" cy="333.8" rx="4.1" ry="6.9"/>
<g id="XMLID_10_">
<path id="XMLID_22_" d="M-298.7,368.6c-1.4-3.8-1.6-12.3,7.4-17.9c7.8-4.9,9.7-6,6.4-17.1l5.1-0.3c3.8,12.9,1.2,15.3-7.9,21
c-7.3,4.6-6.8,11.5-6,13.8L-298.7,368.6z"/>
</g>
</g>
<line id="XMLID_11_" class="st1" x1="-672.3" y1="120.9" x2="-583.8" y2="44"/>
<line id="XMLID_12_" class="st1" x1="-500.8" y1="120.9" x2="-589.3" y2="44"/>
<line id="XMLID_14_" class="st1" x1="-672.3" y1="180.9" x2="-583.8" y2="104"/>
<line id="XMLID_13_" class="st1" x1="-500.8" y1="180.9" x2="-589.3" y2="104"/>
</svg>

Before

Width:  |  Height:  |  Size: 6.0 KiB

View File

@@ -1,93 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 90 90" style="enable-background:new 0 0 90 90;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:none;stroke:#000000;stroke-width:18;stroke-miterlimit:10;}
</style>
<g id="XMLID_40_">
<path id="XMLID_61_" class="st0" d="M15.9,89.9c-1.1-0.2-2.2-0.7-3.1-1.5c-0.5-0.5-1.1-1.2-1.6-1.8c-0.7-0.9-1-2.2-0.8-3.4
c0.2-0.8,0.3-1.6,0.6-2.5c0.4-1.1,0.8-2.1,1.2-3.1l0.1-0.2c0.2-0.5,0.4-1,0.7-1.6l0.4-0.9l0.6-1.3c0.5-1.1,1-2.2,1.5-3.4
c0.6-1.4,1.3-2.7,1.9-4.1c1.2-2.5,2.4-5,3.7-7.4c0.8-1.6,1.5-2.9,2.2-4c0.9-1.5,1.8-3,2.9-4.6c0.5-0.8,1.1-1.6,1.6-2.3
c0.2-0.2,0.4-0.5,0.5-0.7c0-0.1,0-0.2-0.1-0.2c-0.2-0.7-0.4-1.7-0.3-2.9c0-0.1,0.1-0.5,0.1-0.5c0,0-0.1-0.2-0.4-0.5
c-0.5-0.5-1-1-1.5-1.5c-0.6-0.6-1.2-1.2-1.8-1.9c-1.4-1.7-2.9-3.3-4.2-5c-1.5-2.1-3-4.2-4.4-6.2l-0.3-0.5c-1-1.4-1.8-2.8-2.8-4.4
c-1-1.7-2-3.3-3-5c-1-1.7-1.7-3.1-2.4-4.5C6.7,12.6,6,10.9,5.7,9c-0.4-3.3,1.4-5.8,4.6-6.6c0.5-0.1,1-0.2,1.5-0.3l0.1,0
c0.4-0.1,0.9-0.1,1.3,0c1.6,0.2,2.5,1.3,2.8,1.6l0.5,0.5c0.9,0.9,1.8,1.9,2.6,3c1.9,2.4,3.8,5,5.6,7.6c1.6,2.2,3.2,4.6,5,7.3
c1.3,1.9,2.6,4,4,6.4c1.2,1.9,2.3,4,3.2,6.2c0.2,0.6,0.5,1.2,0.8,1.8l0,0c1.2,0.3,2.3,0.8,3.2,1.6c0,0,0,0,0,0
c0.8-0.1,1.6-0.3,2.5-0.5c2.2-0.6,4.5-1.2,6.9-1.5c2.4-0.3,5.2-0.6,8.1-0.8c2.5-0.2,5-0.3,7.4-0.4c2.2-0.1,4.2-0.1,6.1-0.1
c1.9,0,4.1,0,6.3,0.4c0.7,0.1,1.3,0.2,2,0.4c1.2,0.3,2.9,0.8,4.2,2.4c1.1,1.3,1.4,3,0.9,4.7c-0.2,0.7-0.4,1.3-0.6,1.9l-0.1,0.3
c-0.4,1-1.2,2.3-3.3,2.8L81,47.9c-1,0.3-2.1,0.5-3.3,0.7c-3.9,0.5-7.1,0.9-10.1,1.2c-3,0.3-6.1,0.5-8.8,0.7
c-2.1,0.1-4.3,0.2-6.6,0.3c-3.1,0.1-6-0.1-8.8-0.4c-0.5-0.1-0.9-0.1-1.4-0.1c-0.1,0.1-0.1,0.1-0.2,0.2c-0.8,0.9-1.7,1.5-2.8,1.9
c0,0,0,0,0,0.1c-0.2,0.4-0.4,1-0.6,1.6l-0.2,0.6c-0.1,0.4-0.2,0.8-0.4,1.2c-0.3,1.1-0.6,2.2-1,3.3c-0.6,1.7-1.3,3.4-2,5
c-1,2.3-2.1,4.7-3.4,7.2c-0.9,1.8-1.8,3.5-2.7,5.2l-0.2,0.3c-0.7,1.3-1.4,2.7-2.3,4.1c-1.3,2.2-2.7,4.4-4.5,6.4
c-0.7,0.7-1.4,1.2-2,1.6l-0.1,0.1C18.6,89.8,17.3,90.1,15.9,89.9z"/>
<path id="XMLID_513_" class="st0" d="M16.5,76.2c0.6-1.3,1.3-2.9,2-4.6c0.6-1.3,1.2-2.7,1.9-4c1.2-2.5,2.4-4.9,3.6-7.4
c0.6-1.3,1.3-2.6,2.1-3.8c0.9-1.5,1.8-3,2.8-4.4c0.8-1.1,1.6-2.2,2.4-3.3c0.5-0.7,0.5-1.4,0.3-2.2c-0.1-0.7-0.4-1.4-0.3-2.1
c0-0.3,0.1-0.7,0.1-1c0-1.1-0.6-2-1.3-2.8c-1-1.2-2.2-2.2-3.2-3.4c-1.4-1.6-2.7-3.1-4-4.8c-1.6-2.1-3.1-4.4-4.6-6.6
c-0.9-1.4-1.8-2.8-2.7-4.2c-1-1.6-2-3.2-2.9-4.9c-0.8-1.4-1.6-2.8-2.2-4.2C9.8,11.2,9.3,10,9.1,8.6c-0.2-1.5,0.4-2.4,2-2.8
c0.4-0.1,0.9-0.2,1.3-0.2c0.5-0.1,0.8,0.2,1.1,0.5c1,1.1,2,2.1,2.9,3.3c1.9,2.5,3.8,5,5.6,7.5c1.7,2.4,3.3,4.8,4.9,7.2
c1.4,2.1,2.7,4.1,3.9,6.2c1.1,1.9,2.1,3.8,2.9,5.8c0.3,0.8,0.7,1.6,1.1,2.3c0.4,0.9,1.2,1.3,2.1,1.5c0.7,0.2,1.4,0.5,1.9,1
c0.7,0.7,1.6,0.8,2.5,0.7c1-0.1,2-0.3,2.9-0.6c2.1-0.6,4.2-1.1,6.4-1.4c2.7-0.3,5.3-0.6,8-0.8c2.4-0.2,4.9-0.3,7.3-0.4
c2-0.1,4-0.1,5.9-0.1c2.5,0,5,0.1,7.5,0.7c0.9,0.2,1.7,0.5,2.3,1.2c0.4,0.5,0.5,1,0.3,1.6c-0.2,0.6-0.4,1.3-0.6,1.9
c-0.2,0.4-0.5,0.6-0.9,0.7c-1.1,0.3-2.3,0.6-3.4,0.7c-3.3,0.4-6.7,0.8-10,1.2c-2.9,0.3-5.8,0.5-8.6,0.7c-2.1,0.1-4.3,0.2-6.5,0.3
c-2.8,0.1-5.5,0-8.3-0.4c-0.8-0.1-1.6-0.1-2.4-0.1c-0.6,0-1.1,0.4-1.6,0.8c-0.2,0.2-0.4,0.4-0.6,0.6c-0.4,0.5-1,0.8-1.6,1
c-0.8,0.2-1.3,0.8-1.7,1.5c-0.6,0.9-0.8,2-1.1,3c-0.4,1.5-0.8,3-1.3,4.4c-0.6,1.6-1.2,3.2-1.9,4.8c-1.1,2.4-2.2,4.8-3.3,7.1
c-0.9,1.8-1.9,3.6-2.8,5.4c-0.7,1.3-1.4,2.6-2.2,3.9c-1.2,2-2.5,4.1-4.1,5.9c-0.5,0.5-1,0.9-1.6,1.3C17,86.7,16,86.6,15.3,86
c-0.5-0.5-0.9-1-1.3-1.5c-0.1-0.2-0.2-0.5-0.1-0.7c0.1-0.7,0.3-1.4,0.5-2.1c0.3-1.1,0.8-2.1,1.2-3.1C15.8,77.9,16.1,77.2,16.5,76.2
z"/>
</g>
<circle id="XMLID_1_" cx="45" cy="-62.6" r="38.3"/>
<g id="XMLID_30_">
<g id="XMLID_28_">
<path id="XMLID_42_" d="M-320.1,46.7c-2.8,0-3.4-1.6-1.5-3.6l38.4-40.2c1.9-2,5-2,6.9,0l38.4,40.2c1.9,2,1.2,3.6-1.5,3.6H-320.1z"
/>
</g>
<g id="XMLID_29_">
<path id="XMLID_69_" d="M-260.7,87.7c0,1.6-1.3,3-3,3h-32.2c-1.7,0-3-1.4-3-3v-61c0-1.6,1.3-3,3-3h32.2c1.7,0,3,1.4,3,3V87.7z"/>
</g>
</g>
<g id="XMLID_2_">
<ellipse id="XMLID_43_" transform="matrix(0.994 0.109 -0.109 0.994 -3.9525 -4.6899)" class="st0" cx="40.9" cy="-38.5" rx="8.4" ry="5.9"/>
<ellipse id="XMLID_62_" transform="matrix(0.9999 -1.525268e-002 1.525268e-002 0.9999 1.4158 0.6287)" class="st0" cx="41.9" cy="-92.5" rx="8.4" ry="3.9"/>
<ellipse id="XMLID_63_" transform="matrix(0.9809 0.1945 -0.1945 0.9809 -11.5349 -11.0065)" class="st0" cx="50.3" cy="-64.2" rx="8.3" ry="8.3"/>
<ellipse id="XMLID_64_" transform="matrix(0.9925 0.1226 -0.1226 0.9925 -8.1174 -2.8185)" class="st0" cx="18.8" cy="-67.4" rx="6.1" ry="8.3"/>
<ellipse id="XMLID_65_" transform="matrix(0.9882 -0.1532 0.1532 0.9882 11.0552 10.7182)" class="st0" cx="75.1" cy="-66.4" rx="3.6" ry="8.3"/>
</g>
<g id="XMLID_15_">
<g id="XMLID_3_">
<polygon id="XMLID_20_" points="17.1,190.4 7.7,186.5 38.2,114.9 47.5,118.8 "/>
</g>
<g id="XMLID_4_">
<polygon id="XMLID_19_" points="53.4,190.4 44,186.5 74.5,114.9 83.8,118.8 "/>
</g>
<g id="XMLID_5_">
<rect id="XMLID_18_" x="18.2" y="169.9" width="36.4" height="10"/>
</g>
<g id="XMLID_6_">
<rect id="XMLID_17_" x="28.3" y="148.5" width="36.4" height="10"/>
</g>
<g id="XMLID_7_">
<rect id="XMLID_16_" x="36.3" y="127.1" width="36.4" height="10"/>
</g>
</g>
<g id="XMLID_21_">
<ellipse id="XMLID_8_" transform="matrix(0.9364 0.3511 -0.3511 0.9364 89.1972 113.6591)" cx="-268.9" cy="302.8" rx="26.8" ry="26.1"/>
<ellipse id="XMLID_9_" transform="matrix(0.9364 0.3511 -0.3511 0.9364 97.4408 118.2247)" cx="-277.3" cy="327.8" rx="6.9" ry="4.1"/>
<g id="XMLID_10_">
<path id="XMLID_22_" d="M-294.7,362.6c-1.4-3.8-1.6-12.3,7.4-17.9c7.8-4.9,9.7-6,6.4-17.1l5.1-0.3c3.8,12.9,1.2,15.3-7.9,21
c-7.3,4.6-6.8,11.5-6,13.8L-294.7,362.6z"/>
</g>
</g>
<line id="XMLID_11_" class="st1" x1="-668.3" y1="114.9" x2="-579.8" y2="38"/>
<line id="XMLID_12_" class="st1" x1="-496.8" y1="114.9" x2="-585.3" y2="38"/>
<line id="XMLID_14_" class="st1" x1="-668.3" y1="174.9" x2="-579.8" y2="98"/>
<line id="XMLID_13_" class="st1" x1="-496.8" y1="174.9" x2="-585.3" y2="98"/>
</svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -1,92 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 19.0.0, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<svg version="1.1" id="Layer_1" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px"
viewBox="0 0 90 90" style="enable-background:new 0 0 90 90;" xml:space="preserve">
<style type="text/css">
.st0{fill:#FFFFFF;}
.st1{fill:none;stroke:#000000;stroke-width:18;stroke-miterlimit:10;}
</style>
<g id="XMLID_40_">
<path id="XMLID_61_" d="M15.9-20.5c-1.1-0.2-2.2-0.7-3.1-1.5c-0.5-0.5-1.1-1.2-1.6-1.8c-0.7-0.9-1-2.2-0.8-3.4
c0.2-0.8,0.3-1.6,0.6-2.5c0.4-1.1,0.8-2.1,1.2-3.1l0.1-0.2c0.2-0.5,0.4-1,0.7-1.6l0.4-0.9l0.6-1.3c0.5-1.1,1-2.2,1.5-3.4
c0.6-1.4,1.3-2.7,1.9-4.1c1.2-2.5,2.4-5,3.7-7.4c0.8-1.6,1.5-2.9,2.2-4c0.9-1.5,1.8-3,2.9-4.6c0.5-0.8,1.1-1.6,1.6-2.3
c0.2-0.2,0.4-0.5,0.5-0.7c0-0.1,0-0.2-0.1-0.2c-0.2-0.7-0.4-1.7-0.3-2.9c0-0.1,0.1-0.5,0.1-0.5c0,0-0.1-0.2-0.4-0.5
c-0.5-0.5-1-1-1.5-1.5c-0.6-0.6-1.2-1.2-1.8-1.9c-1.4-1.7-2.9-3.3-4.2-5c-1.5-2.1-3-4.2-4.4-6.2l-0.3-0.5c-1-1.4-1.8-2.8-2.8-4.4
c-1-1.7-2-3.3-3-5c-1-1.7-1.7-3.1-2.4-4.5c-0.6-1.4-1.3-3-1.6-4.9c-0.4-3.3,1.4-5.8,4.6-6.6c0.5-0.1,1-0.2,1.5-0.3l0.1,0
c0.4-0.1,0.9-0.1,1.3,0c1.6,0.2,2.5,1.3,2.8,1.6l0.5,0.5c0.9,0.9,1.8,1.9,2.6,3c1.9,2.4,3.8,5,5.6,7.6c1.6,2.2,3.2,4.6,5,7.3
c1.3,1.9,2.6,4,4,6.4c1.2,1.9,2.3,4,3.2,6.2c0.2,0.6,0.5,1.2,0.8,1.8l0,0c1.2,0.3,2.3,0.8,3.2,1.6c0,0,0,0,0,0
c0.8-0.1,1.6-0.3,2.5-0.5c2.2-0.6,4.5-1.2,6.9-1.5c2.4-0.3,5.2-0.6,8.1-0.8c2.5-0.2,5-0.3,7.4-0.4c2.2-0.1,4.2-0.1,6.1-0.1
c1.9,0,4.1,0,6.3,0.4c0.7,0.1,1.3,0.2,2,0.4c1.2,0.3,2.9,0.8,4.2,2.4c1.1,1.3,1.4,3,0.9,4.7c-0.2,0.7-0.4,1.3-0.6,1.9l-0.1,0.3
c-0.4,1-1.2,2.3-3.3,2.8L81-62.5c-1,0.3-2.1,0.5-3.3,0.7c-3.9,0.5-7.1,0.9-10.1,1.2c-3,0.3-6.1,0.5-8.8,0.7
c-2.1,0.1-4.3,0.2-6.6,0.3c-3.1,0.1-6-0.1-8.8-0.4c-0.5-0.1-0.9-0.1-1.4-0.1c-0.1,0.1-0.1,0.1-0.2,0.2c-0.8,0.9-1.7,1.5-2.8,1.9
c0,0,0,0,0,0.1c-0.2,0.4-0.4,1-0.6,1.6l-0.2,0.6c-0.1,0.4-0.2,0.8-0.4,1.2c-0.3,1.1-0.6,2.2-1,3.3c-0.6,1.7-1.3,3.4-2,5
c-1,2.3-2.1,4.7-3.4,7.2c-0.9,1.8-1.8,3.5-2.7,5.2l-0.2,0.3c-0.7,1.3-1.4,2.7-2.3,4.1C25-27.3,23.6-25,21.8-23
c-0.7,0.7-1.4,1.2-2,1.6l-0.1,0.1C18.6-20.6,17.3-20.2,15.9-20.5z"/>
<path id="XMLID_513_" d="M16.5-34.2c0.6-1.3,1.3-2.9,2-4.6c0.6-1.3,1.2-2.7,1.9-4c1.2-2.5,2.4-4.9,3.6-7.4c0.6-1.3,1.3-2.6,2.1-3.8
c0.9-1.5,1.8-3,2.8-4.4c0.8-1.1,1.6-2.2,2.4-3.3c0.5-0.7,0.5-1.4,0.3-2.2c-0.1-0.7-0.4-1.4-0.3-2.1c0-0.3,0.1-0.7,0.1-1
c0-1.1-0.6-2-1.3-2.8c-1-1.2-2.2-2.2-3.2-3.4c-1.4-1.6-2.7-3.1-4-4.8c-1.6-2.1-3.1-4.4-4.6-6.6c-0.9-1.4-1.8-2.8-2.7-4.2
c-1-1.6-2-3.2-2.9-4.9c-0.8-1.4-1.6-2.8-2.2-4.2c-0.6-1.2-1.1-2.5-1.3-3.8c-0.2-1.5,0.4-2.4,2-2.8c0.4-0.1,0.9-0.2,1.3-0.2
c0.5-0.1,0.8,0.2,1.1,0.5c1,1.1,2,2.1,2.9,3.3c1.9,2.5,3.8,5,5.6,7.5c1.7,2.4,3.3,4.8,4.9,7.2c1.4,2.1,2.7,4.1,3.9,6.2
c1.1,1.9,2.1,3.8,2.9,5.8c0.3,0.8,0.7,1.6,1.1,2.3c0.4,0.9,1.2,1.3,2.1,1.5c0.7,0.2,1.4,0.5,1.9,1c0.7,0.7,1.6,0.8,2.5,0.7
c1-0.1,2-0.3,2.9-0.6c2.1-0.6,4.2-1.1,6.4-1.4c2.7-0.3,5.3-0.6,8-0.8c2.4-0.2,4.9-0.3,7.3-0.4c2-0.1,4-0.1,5.9-0.1
c2.5,0,5,0.1,7.5,0.7c0.9,0.2,1.7,0.5,2.3,1.2c0.4,0.5,0.5,1,0.3,1.6c-0.2,0.6-0.4,1.3-0.6,1.9c-0.2,0.4-0.5,0.6-0.9,0.7
c-1.1,0.3-2.3,0.6-3.4,0.7c-3.3,0.4-6.7,0.8-10,1.2c-2.9,0.3-5.8,0.5-8.6,0.7c-2.1,0.1-4.3,0.2-6.5,0.3c-2.8,0.1-5.5,0-8.3-0.4
c-0.8-0.1-1.6-0.1-2.4-0.1c-0.6,0-1.1,0.4-1.6,0.8c-0.2,0.2-0.4,0.4-0.6,0.6c-0.4,0.5-1,0.8-1.6,1c-0.8,0.2-1.3,0.8-1.7,1.5
c-0.6,0.9-0.8,2-1.1,3c-0.4,1.5-0.8,3-1.3,4.4c-0.6,1.6-1.2,3.2-1.9,4.8c-1.1,2.4-2.2,4.8-3.3,7.1c-0.9,1.8-1.9,3.6-2.8,5.4
c-0.7,1.3-1.4,2.6-2.2,3.9c-1.2,2-2.5,4.1-4.1,5.9c-0.5,0.5-1,0.9-1.6,1.3c-0.7,0.5-1.7,0.4-2.4-0.3c-0.5-0.5-0.9-1-1.3-1.5
c-0.1-0.2-0.2-0.5-0.1-0.7c0.1-0.7,0.3-1.4,0.5-2.1c0.3-1.1,0.8-2.1,1.2-3.1C15.8-32.5,16.1-33.2,16.5-34.2z"/>
</g>
<circle id="XMLID_1_" cx="45" cy="-173" r="38.3"/>
<g id="XMLID_30_">
<g id="XMLID_28_">
<path id="XMLID_42_" d="M-320.1,46.7c-2.8,0-3.4-1.6-1.5-3.6l38.4-40.2c1.9-2,5-2,6.9,0l38.4,40.2c1.9,2,1.2,3.6-1.5,3.6H-320.1z"
/>
</g>
<g id="XMLID_29_">
<path id="XMLID_69_" d="M-260.7,87.7c0,1.6-1.3,3-3,3h-32.2c-1.7,0-3-1.4-3-3v-61c0-1.6,1.3-3,3-3h32.2c1.7,0,3,1.4,3,3V87.7z"/>
</g>
</g>
<g id="XMLID_2_">
<ellipse id="XMLID_43_" transform="matrix(0.994 0.109 -0.109 0.994 -15.9843 -5.3475)" class="st0" cx="40.9" cy="-148.9" rx="8.4" ry="5.9"/>
<ellipse id="XMLID_62_" transform="matrix(0.9999 -1.525268e-002 1.525268e-002 0.9999 3.0996 0.6159)" class="st0" cx="41.9" cy="-202.9" rx="8.4" ry="3.9"/>
<ellipse id="XMLID_63_" transform="matrix(0.9809 0.1945 -0.1945 0.9809 -33.0074 -13.1149)" class="st0" cx="50.3" cy="-174.6" rx="8.3" ry="8.3"/>
<ellipse id="XMLID_64_" transform="matrix(0.9925 0.1226 -0.1226 0.9925 -21.6519 -3.6513)" class="st0" cx="18.8" cy="-177.8" rx="6.1" ry="8.3"/>
<ellipse id="XMLID_65_" transform="matrix(0.9882 -0.1532 0.1532 0.9882 27.9691 9.4148)" class="st0" cx="75.1" cy="-176.8" rx="3.6" ry="8.3"/>
</g>
<g id="XMLID_15_">
<g id="XMLID_3_">
<polygon id="XMLID_20_" class="st0" points="17.1,88.3 7.7,84 38.2,3.5 47.5,7.9 "/>
</g>
<g id="XMLID_4_">
<polygon id="XMLID_19_" class="st0" points="53.4,88.3 44,84 74.5,3.5 83.8,7.9 "/>
</g>
<g id="XMLID_5_">
<rect id="XMLID_18_" x="18.2" y="65.3" class="st0" width="36.4" height="11.2"/>
</g>
<g id="XMLID_6_">
<rect id="XMLID_17_" x="28.3" y="41.3" class="st0" width="36.4" height="11.2"/>
</g>
<g id="XMLID_7_">
<rect id="XMLID_16_" x="36.3" y="17.2" class="st0" width="36.4" height="11.2"/>
</g>
</g>
<g id="XMLID_21_">
<ellipse id="XMLID_8_" transform="matrix(0.9364 0.3511 -0.3511 0.9364 89.1972 113.6591)" cx="-268.9" cy="302.8" rx="26.8" ry="26.1"/>
<ellipse id="XMLID_9_" transform="matrix(0.9364 0.3511 -0.3511 0.9364 97.4408 118.2247)" cx="-277.3" cy="327.8" rx="6.9" ry="4.1"/>
<g id="XMLID_10_">
<path id="XMLID_22_" d="M-294.7,362.6c-1.4-3.8-1.6-12.3,7.4-17.9c7.8-4.9,9.7-6,6.4-17.1l5.1-0.3c3.8,12.9,1.2,15.3-7.9,21
c-7.3,4.6-6.8,11.5-6,13.8L-294.7,362.6z"/>
</g>
</g>
<line id="XMLID_11_" class="st1" x1="-668.3" y1="114.9" x2="-579.8" y2="38"/>
<line id="XMLID_12_" class="st1" x1="-496.8" y1="114.9" x2="-585.3" y2="38"/>
<line id="XMLID_14_" class="st1" x1="-668.3" y1="174.9" x2="-579.8" y2="98"/>
<line id="XMLID_13_" class="st1" x1="-496.8" y1="174.9" x2="-585.3" y2="98"/>
</svg>

Before

Width:  |  Height:  |  Size: 6.2 KiB

View File

@@ -52,14 +52,36 @@ var handleMatchTime = function(data) {
// Handles a websocket message to update the match score.
var handleRealtimeScore = function(data) {
$("#redScoreNumber").text(data.RedScoreSummary.Score);
$("#redOwnershipPoints").text(data.RedScoreSummary.OwnershipPoints);
$("#redRotors").text(data.RedScore.AutoRotors + data.RedScore.Rotors);
$("#redTakeoffs").text(data.RedScore.Takeoffs);
$("#blueScoreNumber").text(data.BlueScoreSummary.Score);
$("#blueOwnershipPoints").text(data.BlueScoreSummary.OwnershipPoints);
$("#blueRotors").text(data.BlueScore.AutoRotors + data.BlueScore.Rotors);
$("#blueTakeoffs").text(data.BlueScore.Takeoffs);
$("#redScoreNumber").text(data.Red.Score);
$("#redForceCubesIcon").attr("data-state", data.Red.ForceState);
$("#redForceCubes").text(data.Red.ForceCubes).attr("data-state", data.Red.ForceState);
$("#redLevitateCubesIcon").attr("data-state", data.Red.LevitateState);
$("#redLevitateCubes").text(data.Red.LevitateCubes).attr("data-state", data.Red.LevitateState);
$("#redBoostCubesIcon").attr("data-state", data.Red.BoostState);
$("#redBoostCubes").text(data.Red.BoostCubes).attr("data-state", data.Red.BoostState);
$("#blueScoreNumber").text(data.Blue.Score);
$("#blueForceCubesIcon").attr("data-state", data.Blue.ForceState);
$("#blueForceCubes").text(data.Blue.ForceCubes).attr("data-state", data.Blue.ForceState);
$("#blueLevitateCubesIcon").attr("data-state", data.Blue.LevitateState);
$("#blueLevitateCubes").text(data.Blue.LevitateCubes).attr("data-state", data.Blue.LevitateState);
$("#blueBoostCubesIcon").attr("data-state", data.Blue.BoostState);
$("#blueBoostCubes").text(data.Blue.BoostCubes).attr("data-state", data.Blue.BoostState);
// Switch/scale indicators.
$("#scaleIndicator").attr("data-owned-by", data.ScaleOwnedBy);
$("#redSwitchIndicator").attr("data-owned-by", data.Red.SwitchOwnedBy);
$("#blueSwitchIndicator").attr("data-owned-by", data.Blue.SwitchOwnedBy);
// Power up progress bars.
if ((data.Red.ForceState === 2 || data.Red.BoostState === 2) && $("#redProgress").height() === 0) {
$("#redProgress").height(85);
$("#redProgress").transition({queue: false, height: 0}, 10000, "linear");
}
if ((data.Blue.ForceState === 2 || data.Blue.BoostState === 2) && $("#blueProgress").height() === 0) {
$("#blueProgress").height(85);
$("#blueProgress").transition({queue: false, height: 0}, 10000, "linear");
}
};
// Handles a websocket message to populate the final score data.
@@ -144,9 +166,10 @@ var transitionBlankToIntro = function(callback) {
var transitionIntroToInMatch = function(callback) {
$("#logo").transition({queue: false, top: "10px"}, 500, "ease");
$(".score").transition({queue: false, width: "250px"}, 500, "ease", function() {
$(".score").transition({queue: false, width: "275px"}, 500, "ease", function() {
$(".score-number").transition({queue: false, opacity: 1}, 750, "ease");
$(".score-fields").transition({queue: false, opacity: 1}, 750, "ease");
$(".seesaw-indicator").transition({queue: false, opacity: 1}, 750, "ease");
$("#matchTime").transition({queue: false, opacity: 1}, 750, "ease", callback);
});
};
@@ -165,10 +188,11 @@ var transitionBlankToInMatch = function(callback) {
$("#centering").transition({queue: false, bottom: "0px"}, 500, "ease", function() {
$(".teams").transition({queue: false, width: "65px"}, 100, "linear", function() {
$("#logo").transition({queue: false, top: "10px"}, 500, "ease");
$(".score").transition({queue: false, width: "250px"}, 500, "ease", function() {
$(".score").transition({queue: false, width: "275px"}, 500, "ease", function() {
$("#eventMatchInfo").show();
$(".score-number").transition({queue: false, opacity: 1}, 750, "ease");
$(".score-fields").transition({queue: false, opacity: 1}, 750, "ease");
$(".seesaw-indicator").transition({queue: false, opacity: 1}, 750, "ease");
$("#matchTime").transition({queue: false, opacity: 1}, 750, "ease", callback);
var height = -$("#eventMatchInfo").height();
$("#eventMatchInfo").transition({queue: false, bottom: height + "px"}, 500, "ease", callback);
@@ -180,8 +204,9 @@ var transitionBlankToInMatch = function(callback) {
var transitionInMatchToIntro = function(callback) {
$(".score-number").transition({queue: false, opacity: 0}, 300, "linear");
$(".score-fields").transition({queue: false, opacity: 0}, 300, "linear");
$(".seesaw-indicator").transition({queue: false, opacity: 0}, 300, "linear");
$("#matchTime").transition({queue: false, opacity: 0}, 300, "linear", function() {
$("#logo").transition({queue: false, top: "30px"}, 500, "ease");
$("#logo").transition({queue: false, top: "35px"}, 500, "ease");
$(".score").transition({queue: false, width: "120px"}, 500, "ease");
$(".teams").transition({queue: false, width: "65px"}, 500, "ease", callback);
});
@@ -191,9 +216,10 @@ var transitionInMatchToBlank = function(callback) {
$("#eventMatchInfo").transition({queue: false, bottom: "0px"}, 500, "ease");
$("#matchTime").transition({queue: false, opacity: 0}, 300, "linear");
$(".score-fields").transition({queue: false, opacity: 0}, 300, "linear");
$(".seesaw-indicator").transition({queue: false, opacity: 0}, 300, "linear");
$(".score-number").transition({queue: false, opacity: 0}, 300, "linear", function() {
$("#eventMatchInfo").hide();
$("#logo").transition({queue: false, top: "30px"}, 500, "ease");
$("#logo").transition({queue: false, top: "35px"}, 500, "ease");
$(".score").transition({queue: false, width: "0px"}, 500, "ease");
$(".teams").transition({queue: false, width: "40px"}, 500, "ease", function() {
$("#centering").transition({queue: false, bottom: "-340px"}, 1000, "ease", callback);

View File

@@ -26,35 +26,41 @@
<div class="score" id="redScore">
<div class="score-fields score-fields-icons">
<span class="valign-cell">
<img class="score-icon" src="/static/img/pressure.svg" /><br />
<img class="score-icon" src="/static/img/rotor.svg" /><br />
<img class="score-icon" src="/static/img/takeoff.svg" />
<span class="power-up" id="redForceCubesIcon">F</span><br />
<span class="power-up" id="redLevitateCubesIcon">L</span><br />
<span class="power-up" id="redBoostCubesIcon">B</span>
</span>
</div>
<div class="score-fields score-fields-text">
<span class="valign-cell">
<span id="redPressurePoints"></span><br />
<span id="redRotors"></span><br />
<span id="redTakeoffs"></span>
<span class="power-up" id="redForceCubes"></span><br />
<span class="power-up" id="redLevitateCubes"></span><br />
<span class="power-up" id="redBoostCubes"></span>
</span>
</div>
<div class="powerup-progress">
<div id="redProgress"></div>
</div>
<div class="score-number" id="redScoreNumber">&nbsp;</div>
</div>
<div class="score" id="blueScore">
<div class="score-fields score-fields-icons pull-right">
<span class="valign-cell">
<img class="score-icon score-icon-right" src="/static/img/pressure.svg" /><br />
<img class="score-icon score-icon-right" src="/static/img/rotor.svg" /><br />
<img class="score-icon score-icon-right" src="/static/img/takeoff.svg" />
<span class="power-up" id="blueForceCubesIcon">F</span><br />
<span class="power-up" id="blueLevitateCubesIcon">L</span><br />
<span class="power-up" id="blueBoostCubesIcon">B</span>
</span>
</div>
<div class="score-fields score-fields-text pull-right" style="direction: rtl;">
<span class="valign-cell" style="text-align: right;">
<span id="bluePressurePoints"></span><br />
<span id="blueRotors"></span><br />
<span id="blueTakeoffs"></span>
<span class="power-up" id="blueForceCubes"></span><br />
<span class="power-up" id="blueLevitateCubes"></span><br />
<span class="power-up" id="blueBoostCubes"></span>
</span>
</div>
<div class="powerup-progress pull-right">
<div id="blueProgress"></div>
</div>
<div class="score-number pull-right" id="blueScoreNumber">&nbsp;</div>
</div>
<div class="teams" id="blueTeams">
@@ -72,6 +78,9 @@
<div class="text-center" id="matchCircle">
<img id="logo" src="/static/img/game-logo.png" alt="logo" />
<div id="matchTime"></div>
<div class="seesaw-indicator" id="redSwitchIndicator"></div>
<div class="seesaw-indicator" id="scaleIndicator"></div>
<div class="seesaw-indicator" id="blueSwitchIndicator"></div>
</div>
</div>
<div id="blindsContainer">
@@ -163,6 +172,9 @@
<audio id="match-end" src="/static/audio/match_end.wav" preload="auto"></audio>
<audio id="match-abort" src="/static/audio/match_abort.mp3" preload="auto"></audio>
<audio id="match-resume" src="/static/audio/match_resume.wav" preload="auto"></audio>
<audio id="match-force" src="/static/audio/match_force.wav" preload="auto"></audio>
<audio id="match-levitate" src="/static/audio/match_levitate.wav" preload="auto"></audio>
<audio id="match-boost" src="/static/audio/match_boost.wav" preload="auto"></audio>
<audio id="match-endgame" src="/static/audio/match_endgame.wav" preload="auto"></audio>
<script src="/static/js/lib/jquery.min.js"></script>
<script src="/static/js/lib/jquery.json-2.4.min.js"></script>

View File

@@ -11,8 +11,26 @@ import (
"io"
"log"
"net/http"
"time"
)
type audienceScoreFields struct {
Red *audienceAllianceScoreFields
Blue *audienceAllianceScoreFields
ScaleOwnedBy game.Alliance
}
type audienceAllianceScoreFields struct {
Score int
ForceCubes int
LevitateCubes int
BoostCubes int
ForceState game.PowerUpState
LevitateState game.PowerUpState
BoostState game.PowerUpState
SwitchOwnedBy game.Alliance
}
// Renders the audience display to be chroma keyed over the video feed.
func (web *Web) audienceDisplayHandler(w http.ResponseWriter, r *http.Request) {
if !web.userIsReader(w, r) {
@@ -93,13 +111,7 @@ func (web *Web) audienceDisplayWebsocketHandler(w http.ResponseWriter, r *http.R
log.Printf("Websocket error: %s", err)
return
}
data = struct {
RedScore *game.Score
BlueScore *game.Score
RedScoreSummary *game.ScoreSummary
BlueScoreSummary *game.ScoreSummary
}{&web.arena.RedRealtimeScore.CurrentScore, &web.arena.BlueRealtimeScore.CurrentScore,
web.arena.RedScoreSummary(), web.arena.BlueScoreSummary()}
data = web.getAudienceScoreFields()
err = websocket.Write("realtimeScore", data)
if err != nil {
log.Printf("Websocket error: %s", err)
@@ -155,13 +167,7 @@ func (web *Web) audienceDisplayWebsocketHandler(w http.ResponseWriter, r *http.R
return
}
messageType = "realtimeScore"
message = struct {
RedScore *game.Score
BlueScore *game.Score
RedScoreSummary *game.ScoreSummary
BlueScoreSummary *game.ScoreSummary
}{&web.arena.RedRealtimeScore.CurrentScore, &web.arena.BlueRealtimeScore.CurrentScore,
web.arena.RedScoreSummary(), web.arena.BlueScoreSummary()}
message = web.getAudienceScoreFields()
case _, ok := <-scorePostedListener:
if !ok {
return
@@ -220,3 +226,41 @@ func (web *Web) audienceDisplayWebsocketHandler(w http.ResponseWriter, r *http.R
}
}
}
// Constructs the data object sent to the audience display for the realtime scoring overlay.
func (web *Web) getAudienceScoreFields() *audienceScoreFields {
fields := new(audienceScoreFields)
fields.Red = getAudienceAllianceScoreFields(&web.arena.RedRealtimeScore.CurrentScore, web.arena.RedScoreSummary(),
web.arena.RedVault, web.arena.RedSwitch)
fields.Blue = getAudienceAllianceScoreFields(&web.arena.BlueRealtimeScore.CurrentScore,
web.arena.BlueScoreSummary(), web.arena.BlueVault, web.arena.BlueSwitch)
fields.ScaleOwnedBy = web.arena.Scale.GetOwnedBy()
return fields
}
// Constructs the data object for one alliance sent to the audience display for the realtime scoring overlay.
func getAudienceAllianceScoreFields(allianceScore *game.Score, allianceScoreSummary *game.ScoreSummary,
allianceVault *game.Vault, allianceSwitch *game.Seesaw) *audienceAllianceScoreFields {
fields := new(audienceAllianceScoreFields)
fields.Score = allianceScoreSummary.Score
fields.ForceCubes = allianceScore.ForceCubes
fields.LevitateCubes = allianceScore.LevitateCubes
fields.BoostCubes = allianceScore.BoostCubes
if allianceVault.ForcePowerUp != nil {
fields.ForceState = allianceVault.ForcePowerUp.GetState(time.Now())
} else {
fields.ForceState = game.Unplayed
}
if allianceVault.LevitatePlayed {
fields.LevitateState = game.Expired
} else {
fields.LevitateState = game.Unplayed
}
if allianceVault.BoostPowerUp != nil {
fields.BoostState = allianceVault.BoostPowerUp.GetState(time.Now())
} else {
fields.BoostState = game.Unplayed
}
fields.SwitchOwnedBy = allianceSwitch.GetOwnedBy()
return fields
}