/// The players currently viewing (but not playing) the active session of NT-BG.
/// </summary>
public readonly List<ICommonSession> Spectators = new();
+
+ /// <summary>
+ /// Whether the game machine should thank (or otherwise talk to) the player when they leave
+ /// </summary>
+ public bool ShouldSayThankYou;
}
using Content.Server.Power.Components;
using Content.Shared.UserInterface;
+using Content.Server.Advertise;
using Content.Shared.Arcade;
using Robust.Server.GameObjects;
using Robust.Shared.Player;
public sealed class BlockGameArcadeSystem : EntitySystem
{
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
+ [Dependency] private readonly AdvertiseSystem _advertise = default!;
public override void Initialize()
{
UpdatePlayerStatus(uid, component.Player, blockGame: component);
}
else
+ {
+ // Everybody's gone
component.Player = null;
+ if (component.ShouldSayThankYou && TryComp<AdvertiseComponent>(uid, out var advertise))
+ {
+ _advertise.SayThankYou(uid, advertise);
+ component.ShouldSayThankYou = false;
+ }
+ }
UpdatePlayerStatus(uid, temp, blockGame: component);
}
_uiSystem.CloseAll(bui);
component.Player = null;
component.Spectators.Clear();
+ component.ShouldSayThankYou = false;
}
private void OnPlayerAction(EntityUid uid, BlockGameArcadeComponent component, BlockGameMessages.BlockGamePlayerActionMessage msg)
return;
}
+ component.ShouldSayThankYou = true;
+
component.Game.ProcessInput(msg.PlayerAction);
}
}
/// </summary>
[ViewVariables(VVAccess.ReadWrite)]
public int RewardAmount = 0;
+
+ /// <summary>
+ /// Whether the game machine should thank (or otherwise talk to) the player when they leave
+ /// </summary>
+ public bool ShouldSayThankYou;
}
using Content.Server.Power.Components;
using Content.Shared.UserInterface;
+using Content.Server.Advertise;
using static Content.Shared.Arcade.SharedSpaceVillainArcadeComponent;
using Robust.Server.GameObjects;
using Robust.Shared.Audio;
[Dependency] private readonly IRobustRandom _random = default!;
[Dependency] private readonly SharedAudioSystem _audioSystem = default!;
[Dependency] private readonly UserInterfaceSystem _uiSystem = default!;
+ [Dependency] private readonly AdvertiseSystem _advertise = default!;
public override void Initialize()
{
SubscribeLocalEvent<SpaceVillainArcadeComponent, AfterActivatableUIOpenEvent>(OnAfterUIOpenSV);
SubscribeLocalEvent<SpaceVillainArcadeComponent, SpaceVillainArcadePlayerActionMessage>(OnSVPlayerAction);
SubscribeLocalEvent<SpaceVillainArcadeComponent, PowerChangedEvent>(OnSVillainPower);
+ SubscribeLocalEvent<SpaceVillainArcadeComponent, BoundUIClosedEvent>(OnBoundUIClosed);
}
/// <summary>
case PlayerAction.Heal:
case PlayerAction.Recharge:
component.Game.ExecutePlayerAction(uid, msg.PlayerAction, component);
+ component.ShouldSayThankYou = true; // Any sort of gameplay action counts
break;
case PlayerAction.NewGame:
_audioSystem.PlayPvs(component.NewGameSound, uid, AudioParams.Default.WithVolume(-4f));
if (_uiSystem.TryGetUi(uid, SpaceVillainArcadeUiKey.Key, out var bui))
_uiSystem.CloseAll(bui);
+
+ component.ShouldSayThankYou = false;
+ }
+
+ private void OnBoundUIClosed(Entity<SpaceVillainArcadeComponent> ent, ref BoundUIClosedEvent args)
+ {
+ if (args.UiKey is not SpaceVillainArcadeUiKey || (SpaceVillainArcadeUiKey) args.UiKey != SpaceVillainArcadeUiKey.Key)
+ return;
+
+ if (ent.Comp.ShouldSayThankYou && TryComp<AdvertiseComponent>(ent.Owner, out var advertise))
+ {
+ _advertise.SayThankYou(ent.Owner, advertise);
+ ent.Comp.ShouldSayThankYou = false;
+ }
}
}
using Content.Server.Popups;
-using Content.Server.Sound.Components;
+using Content.Server.Sound;
+using Content.Shared.Sound.Components;
using Content.Shared.Actions;
using Content.Shared.Audio;
using Content.Shared.Bed.Sleep;
[Dependency] private readonly PopupSystem _popupSystem = default!;
[Dependency] private readonly SharedAudioSystem _audio = default!;
[Dependency] private readonly StatusEffectsSystem _statusEffectsSystem = default!;
+ [Dependency] private readonly EmitSoundSystem _emitSound = default!;
[ValidatePrototypeId<EntityPrototype>] public const string SleepActionId = "ActionSleep";
{
emitSound.Sound = sleepSound.Snore;
}
- emitSound.PlayChance = sleepSound.Chance;
- emitSound.RollInterval = sleepSound.Interval;
+ emitSound.MinInterval = sleepSound.Interval;
+ emitSound.MaxInterval = sleepSound.MaxInterval;
emitSound.PopUp = sleepSound.PopUp;
}
return;
}
if (TryComp<SpamEmitSoundComponent>(uid, out var spam))
- spam.Enabled = args.NewMobState == MobState.Alive;
+ _emitSound.SetEnabled((uid, spam), args.NewMobState == MobState.Alive);
}
private void AddWakeVerb(EntityUid uid, SleepingComponent component, GetVerbsEvent<AlternativeVerb> args)
+++ /dev/null
-using Content.Shared.Sound.Components;
-
-namespace Content.Server.Sound.Components
-{
- /// <summary>
- /// Rolls to play a sound every few seconds.
- /// </summary>
- [RegisterComponent]
- public sealed partial class SpamEmitSoundComponent : BaseEmitSoundComponent
- {
- [DataField("accumulator")]
- public float Accumulator = 0f;
-
- [DataField("rollInterval")]
- public float RollInterval = 2f;
-
- [DataField("playChance")]
- public float PlayChance = 0.5f;
-
- // Always Pvs.
- [DataField("popUp")]
- public string? PopUp;
-
- [DataField("enabled")]
- public bool Enabled = true;
- }
-}
using Content.Server.Sound.Components;
using Content.Shared.UserInterface;
using Content.Shared.Sound;
-using Robust.Shared.Random;
+using Content.Shared.Sound.Components;
+using Robust.Shared.Timing;
+using Robust.Shared.Network;
namespace Content.Server.Sound;
public sealed class EmitSoundSystem : SharedEmitSoundSystem
{
+ [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] private readonly INetManager _net = default!;
+
public override void Update(float frameTime)
{
base.Update(frameTime);
if (!soundSpammer.Enabled)
continue;
- soundSpammer.Accumulator += frameTime;
- if (soundSpammer.Accumulator < soundSpammer.RollInterval)
- {
- continue;
- }
- soundSpammer.Accumulator -= soundSpammer.RollInterval;
-
- if (Random.Prob(soundSpammer.PlayChance))
+ if (_timing.CurTime >= soundSpammer.NextSound)
{
if (soundSpammer.PopUp != null)
Popup.PopupEntity(Loc.GetString(soundSpammer.PopUp), uid);
TryEmitSound(uid, soundSpammer, predict: false);
+
+ SpamEmitSoundReset((uid, soundSpammer));
}
}
}
SubscribeLocalEvent<EmitSoundOnTriggerComponent, TriggerEvent>(HandleEmitSoundOnTrigger);
SubscribeLocalEvent<EmitSoundOnUIOpenComponent, AfterActivatableUIOpenEvent>(HandleEmitSoundOnUIOpen);
+
+ SubscribeLocalEvent<SpamEmitSoundComponent, MapInitEvent>(HandleSpamEmitSoundMapInit);
}
private void HandleEmitSoundOnUIOpen(EntityUid uid, EmitSoundOnUIOpenComponent component, AfterActivatableUIOpenEvent args)
TryEmitSound(uid, component, args.User, false);
args.Handled = true;
}
+
+ private void HandleSpamEmitSoundMapInit(Entity<SpamEmitSoundComponent> entity, ref MapInitEvent args)
+ {
+ SpamEmitSoundReset(entity);
+
+ // Prewarm so multiple entities have more variation.
+ entity.Comp.NextSound -= Random.Next(entity.Comp.MaxInterval);
+ Dirty(entity);
+ }
+
+ private void SpamEmitSoundReset(Entity<SpamEmitSoundComponent> entity)
+ {
+ if (_net.IsClient)
+ return;
+
+ entity.Comp.NextSound = _timing.CurTime + ((entity.Comp.MinInterval < entity.Comp.MaxInterval)
+ ? Random.Next(entity.Comp.MinInterval, entity.Comp.MaxInterval)
+ : entity.Comp.MaxInterval);
+
+ Dirty(entity);
+ }
+
+ public override void SetEnabled(Entity<SpamEmitSoundComponent?> entity, bool enabled)
+ {
+ if (!Resolve(entity, ref entity.Comp, false))
+ return;
+
+ if (entity.Comp.Enabled == enabled)
+ return;
+
+ entity.Comp.Enabled = enabled;
+
+ if (enabled)
+ SpamEmitSoundReset((entity, entity.Comp));
+ }
}
--- /dev/null
+using Content.Server.Power.Components;
+using Content.Server.Power.EntitySystems;
+using Content.Shared.Sound;
+using Content.Shared.Sound.Components;
+
+namespace Content.Server.Sound;
+
+public sealed partial class SpamEmitSoundRequirePowerSystem : SharedSpamEmitSoundRequirePowerSystem
+{
+ public override void Initialize()
+ {
+ base.Initialize();
+
+ SubscribeLocalEvent<SpamEmitSoundRequirePowerComponent, PowerChangedEvent>(OnPowerChanged);
+ SubscribeLocalEvent<SpamEmitSoundRequirePowerComponent, PowerNetBatterySupplyEvent>(OnPowerSupply);
+ }
+
+ private void OnPowerChanged(Entity<SpamEmitSoundRequirePowerComponent> entity, ref PowerChangedEvent args)
+ {
+ if (TryComp<SpamEmitSoundComponent>(entity.Owner, out var comp))
+ {
+ EmitSound.SetEnabled((entity, comp), args.Powered);
+ }
+ }
+
+ private void OnPowerSupply(Entity<SpamEmitSoundRequirePowerComponent> entity, ref PowerNetBatterySupplyEvent args)
+ {
+ if (TryComp<SpamEmitSoundComponent>(entity.Owner, out var comp))
+ {
+ EmitSound.SetEnabled((entity, comp), args.Supply);
+ }
+ }
+}
public SoundSpecifier Snore = new SoundCollectionSpecifier("Snores", AudioParams.Default.WithVariation(0.2f));
/// <summary>
- /// Interval between snore attempts in seconds
+ /// Minimum interval between snore attempts in seconds
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
- public float Interval = 5f;
+ public TimeSpan Interval = TimeSpan.FromSeconds(5);
/// <summary>
- /// Chance for snore attempt to succeed
+ /// Maximum interval between snore attempts in seconds
/// </summary>
[DataField, ViewVariables(VVAccess.ReadWrite)]
- public float Chance = 0.33f;
+ public TimeSpan MaxInterval = TimeSpan.FromSeconds(15);
/// <summary>
/// Popup for snore (e.g. Zzz...)
--- /dev/null
+using Robust.Shared.GameStates;
+
+namespace Content.Shared.Sound.Components;
+
+/// <summary>
+/// Repeatedly plays a sound with a randomized delay.
+/// </summary>
+[RegisterComponent, NetworkedComponent]
+[AutoGenerateComponentState, AutoGenerateComponentPause]
+public sealed partial class SpamEmitSoundComponent : BaseEmitSoundComponent
+{
+ /// <summary>
+ /// The time at which the next sound will play.
+ /// </summary>
+ [DataField, AutoPausedField, AutoNetworkedField]
+ public TimeSpan NextSound;
+
+ /// <summary>
+ /// The minimum time in seconds between playing the sound.
+ /// </summary>
+ [DataField]
+ public TimeSpan MinInterval = TimeSpan.FromSeconds(2);
+
+ /// <summary>
+ /// The maximum time in seconds between playing the sound.
+ /// </summary>
+ [DataField]
+ public TimeSpan MaxInterval = TimeSpan.FromSeconds(2);
+
+ // Always Pvs.
+ /// <summary>
+ /// Content of a popup message to display whenever the sound plays.
+ /// </summary>
+ [DataField]
+ public LocId? PopUp;
+
+ /// <summary>
+ /// Whether the timer is currently running and sounds are being played.
+ /// Do not set this directly, use <see cref="EmitSoundSystem.SetEnabled"/>
+ /// </summary>
+ [DataField, AutoNetworkedField]
+ [Access(typeof(SharedEmitSoundSystem))]
+ public bool Enabled = true;
+}
--- /dev/null
+namespace Content.Shared.Sound.Components;
+
+/// <summary>
+/// Enables or disables an SpamEmitSound component depending
+/// on the powered state of the entity.
+/// </summary>
+[RegisterComponent]
+public sealed partial class SpamEmitSoundRequirePowerComponent : Component
+{
+}
[UsedImplicitly]
public abstract class SharedEmitSoundSystem : EntitySystem
{
- [Dependency] private readonly IGameTiming _timing = default!;
+ [Dependency] protected readonly IGameTiming Timing = default!;
[Dependency] private readonly INetManager _netMan = default!;
[Dependency] private readonly ITileDefinitionManager _tileDefMan = default!;
[Dependency] protected readonly IRobustRandom Random = default!;
!args.OtherFixture.Hard ||
!TryComp<PhysicsComponent>(uid, out var physics) ||
physics.LinearVelocity.Length() < component.MinimumVelocity ||
- _timing.CurTime < component.NextSound ||
+ Timing.CurTime < component.NextSound ||
MetaData(uid).EntityPaused)
{
return;
var fraction = MathF.Min(1f, (physics.LinearVelocity.Length() - component.MinimumVelocity) / MaxVolumeVelocity);
var volume = MinVolume + (MaxVolume - MinVolume) * fraction;
- component.NextSound = _timing.CurTime + EmitSoundOnCollideComponent.CollideCooldown;
+ component.NextSound = Timing.CurTime + EmitSoundOnCollideComponent.CollideCooldown;
var sound = component.Sound;
if (_netMan.IsServer && sound != null)
_audioSystem.PlayPvs(_audioSystem.GetSound(sound), uid, AudioParams.Default.WithVolume(volume));
}
}
+
+ public virtual void SetEnabled(Entity<SpamEmitSoundComponent?> entity, bool enabled)
+ {
+ }
}
--- /dev/null
+namespace Content.Shared.Sound;
+
+public abstract partial class SharedSpamEmitSoundRequirePowerSystem : EntitySystem
+{
+ [Dependency] protected readonly SharedEmitSoundSystem EmitSound = default!;
+}
--- /dev/null
+- files: ["hahaha.ogg", "pew_pew.ogg", "sting_*.ogg"]
+ license: "CC0-1.0"
+ copyright: "Recorded by https://github.com/Tayrtahn"
+ source: "https://github.com/space-wizards/space-station-14/pull/24200"
--- /dev/null
+advertisement-block-game-1 = Legally distinct!
+advertisement-block-game-2 = What the hell is a T-spin?
+advertisement-block-game-3 = These blocks aren't going to clear themselves!
+advertisement-block-game-4 = Beep boop! Bwoooop!
+advertisement-block-game-5 = Let's play a game!
+advertisement-block-game-6 = 6 whole colors of gameplay!
+advertisement-block-game-7 = Hot 8-bit action!
+advertisement-block-game-8 = Blocks, blocks, blocks!
+advertisement-block-game-9 = Think YOU can claim the high score?
+advertisement-block-game-10 = Nanotrasen Block Game IS what TetrISN'T!
+advertisement-block-game-11 = Now with blast processing!
+advertisement-block-game-12 = Our lawyers are standing by!
+advertisement-block-game-13 = Hallelujah, it's raining blocks!
+
+thankyou-block-game-1 = Play again soon!
+thankyou-block-game-2 = Well played!
+thankyou-block-game-3 = Just one more game?
+thankyou-block-game-4 = Stopping so soon?
+thankyou-block-game-5 = The blocks will miss you.
+thankyou-block-game-6 = Thanks for playin'!
+thankyou-block-game-7 = Come back soon!
+thankyou-block-game-8 = Beep bwooop!
+thankyou-block-game-9 = There's always time for another game!
+thankyou-block-game-10 = Don't give up now!
+thankyou-block-game-11 = There are always more blocks!
+thankyou-block-game-12 = The blocks await your return!
--- /dev/null
+advertisement-space-villain-1 = Are you a bad enough dude to beat this game?
+advertisement-space-villain-2 = Beat the bad guy; win a prize!
+advertisement-space-villain-3 = FIGHT ME!
+advertisement-space-villain-4 = Space needs a hero!
+advertisement-space-villain-5 = I'm holding out for a hero!
+advertisement-space-villain-6 = Won't someone save us?
+advertisement-space-villain-7 = Mua-hah-hah-hah!
+advertisement-space-villain-8 = Spaaaaaaaace Villain!
+advertisement-space-villain-9 = No one can defeat me!
+advertisement-space-villain-10 = Tremble before me!
+advertisement-space-villain-11 = CHALLENGE ME!
+advertisement-space-villain-12 = FEAR ME!
+advertisement-space-villain-13 = Do you dare to face me in battle!?
+advertisement-space-villain-14 = Beware, I live!
+advertisement-space-villain-15 = I hunger!
+
+thankyou-space-villain-1 = And where do you think you're going, punk?
+thankyou-space-villain-2 = Is that all you've got?
+thankyou-space-villain-3 = This fight isn't over!
+thankyou-space-villain-4 = Challenge again soon!
+thankyou-space-villain-5 = Who dares to challenge me next?
+thankyou-space-villain-6 = I knew you couldn't defeat me!
+thankyou-space-villain-7 = Too much for you to handle?
+thankyou-space-villain-8 = Run, coward!
+thankyou-space-villain-9 = You never stood a chance.
+thankyou-space-villain-10 = Care for a rematch?
+thankyou-space-villain-11 = Fight me again!
+thankyou-space-villain-12 = Come back here and fight me!
--- /dev/null
+- type: advertisementsPack
+ id: BlockGameAds
+ advertisements:
+ - advertisement-block-game-1
+ - advertisement-block-game-2
+ - advertisement-block-game-3
+ - advertisement-block-game-4
+ - advertisement-block-game-5
+ - advertisement-block-game-6
+ - advertisement-block-game-7
+ - advertisement-block-game-8
+ - advertisement-block-game-9
+ - advertisement-block-game-10
+ - advertisement-block-game-11
+ - advertisement-block-game-12
+ - advertisement-block-game-13
+ thankyous:
+ - thankyou-block-game-1
+ - thankyou-block-game-2
+ - thankyou-block-game-3
+ - thankyou-block-game-4
+ - thankyou-block-game-5
+ - thankyou-block-game-6
+ - thankyou-block-game-7
+ - thankyou-block-game-8
+ - thankyou-block-game-9
+ - thankyou-block-game-10
+ - thankyou-block-game-11
+ - thankyou-block-game-12
--- /dev/null
+- type: advertisementsPack
+ id: SpaceVillainAds
+ advertisements:
+ - advertisement-space-villain-1
+ - advertisement-space-villain-2
+ - advertisement-space-villain-3
+ - advertisement-space-villain-4
+ - advertisement-space-villain-5
+ - advertisement-space-villain-6
+ - advertisement-space-villain-7
+ - advertisement-space-villain-8
+ - advertisement-space-villain-9
+ - advertisement-space-villain-10
+ - advertisement-space-villain-11
+ - advertisement-space-villain-12
+ - advertisement-space-villain-13
+ - advertisement-space-villain-14
+ - advertisement-space-villain-15
+ thankyous:
+ - thankyou-space-villain-1
+ - thankyou-space-villain-2
+ - thankyou-space-villain-3
+ - thankyou-space-villain-4
+ - thankyou-space-villain-5
+ - thankyou-space-villain-6
+ - thankyou-space-villain-7
+ - thankyou-space-villain-8
+ - thankyou-space-villain-9
+ - thankyou-space-villain-10
+ - thankyou-space-villain-11
+ - thankyou-space-villain-12
priority: Low
- type: ExtensionCableReceiver
- type: PointLight
- radius: 1.5
+ radius: 1.8
energy: 1.6
color: "#3db83b"
+ - type: LitOnPowered
- type: Sprite
sprite: Structures/Machines/arcade.rsi
layers:
- map: ["computerLayerBody"]
state: arcade
- map: ["computerLayerScreen"]
- state: invaders
+ state: screen_invaders
+ - map: ["enum.WiresVisualLayers.MaintenancePanel"]
+ state: panel
+ visible: false
- type: Icon
sprite: Structures/Machines/arcade.rsi
state: arcade
+ - type: WiresPanel
+ - type: Wires
+ layoutId: Arcade
+ boardName: wires-board-name-arcade
+ - type: WiresVisuals
+ - type: TypingIndicator
+ proto: robot
+ - type: Speech
+ speechVerb: Robotic
+ speechSounds: Vending
- type: Anchorable
- type: Pullable
- type: StaticPrice
price: 300
+ - type: SpamEmitSoundRequirePower
+ - type: SpamEmitSound
+ minInterval: 30
+ maxInterval: 90
+ sound:
+ collection: ArcadeNoise
+ params:
+ volume: -8
+ maxDistance: 10
+ variation: 0.05
- type: entity
id: SpaceVillainArcade
name: space villain arcade
parent: ArcadeBase
components:
+ - type: Sprite
+ sprite: Structures/Machines/arcade.rsi
+ layers:
+ - map: ["computerLayerBody"]
+ state: arcade
+ - map: ["computerLayerScreen"]
+ state: screen_spacevillain
+ - map: ["enum.WiresVisualLayers.MaintenancePanel"]
+ state: panel
+ visible: false
+ - type: PointLight
+ color: "#e3a136"
- type: SpaceVillainArcade
rewardAmount: 0
possibleRewards:
type: WiresBoundUserInterface
- type: Computer
board: SpaceVillainArcadeComputerCircuitboard
+ - type: Advertise
+ pack: SpaceVillainAds
+ minWait: 60 # Arcades are noisy
+ maxWait: 240
- type: entity
id: SpaceVillainArcadeFilled
- map: ["computerLayerBody"]
state: arcade
- map: ["computerLayerScreen"]
- state: blockgame
+ state: screen_blockgame
+ - map: ["enum.WiresVisualLayers.MaintenancePanel"]
+ state: panel
+ visible: false
- type: BlockGameArcade
- type: ActivatableUI
key: enum.BlockGameUiKey.Key
- type: ActivatableUIRequiresPower
- - type: WiresPanel
- - type: Wires
- layoutId: Arcade
- boardName: wires-board-name-arcade
- type: UserInterface
interfaces:
- key: enum.BlockGameUiKey.Key
type: WiresBoundUserInterface
- type: Computer
board: BlockGameArcadeComputerCircuitboard
+ - type: Advertise
+ pack: BlockGameAds
+ minWait: 60 # Arcades are noisy
+ maxWait: 240
- type: SleepEmitSound
snore: /Audio/Voice/Misc/silly_snore.ogg
interval: 10
- chance: 1.0
- !type:AddImplantSpecial
implants: [ SadTromboneImplant ]
--- /dev/null
+- type: soundCollection
+ id: ArcadeNoise
+ files:
+ - /Audio/Machines/Arcade/hahaha.ogg
+ - /Audio/Machines/Arcade/pew_pew.ogg
+ - /Audio/Machines/Arcade/sting_01.ogg
+ - /Audio/Machines/Arcade/sting_02.ogg
+ - /Audio/Machines/Arcade/sting_03.ogg
+ - /Audio/Machines/Arcade/sting_04.ogg
+ - /Audio/Machines/Arcade/sting_05.ogg
+ - /Audio/Machines/Arcade/sting_06.ogg
id: Arcade
wires:
- !type:PowerWireAction
+ - !type:SpeechWireAction
- !type:ArcadeOverflowWireAction
- !type:ArcadePlayerInvincibleWireAction
- !type:ArcadeEnemyInvincibleWireAction
"directions": 4
},
{
- "name": "invaders",
+ "name": "panel",
+ "directions": 4
+ },
+ {
+ "name": "screen_invaders",
"directions": 4,
"delays": [
[
]
},
{
- "name": "blockgame",
+ "name": "screen_blockgame",
"directions": 4,
"delays": [
[
4.8
]
]
+ },
+ {
+ "name": "screen_spacevillain",
+ "directions": 4,
+ "delays": [
+ [
+ 1.0,
+ 0.8,
+ 0.2,
+ 0.8,
+ 0.5,
+ 1.0,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.5,
+ 1.0,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.1,
+ 0.2,
+ 0.5,
+ 0.1,
+ 0.8,
+ 1.0
+ ],
+ [
+ 9.6
+ ],
+ [
+ 9.6
+ ],
+ [
+ 9.6
+ ]
+ ]
}
]
}