From ecbff409b6ef7b54a0033afb816a5ba43b0862a4 Mon Sep 17 00:00:00 2001 From: Tayrtahn Date: Thu, 10 Jul 2025 14:12:24 -0400 Subject: [PATCH] Replace `AdvertiseComponent` with `DatasetVocalizerComponent` (#38887) * Replace AdvertiseComponent with DatasetVocalizerComponent * No vocalizing while broken or without power * Kill AdvertiseComponent/System * This really shouldn't be here * xmldoc for VocalizerRequiresPowerComponent * TryIndex -> Index --- .../Components/AdvertiseComponent.cs | 47 ---- .../EntitySystems/AdvertiseSystem.cs | 106 --------- .../VendingMachines/VendingMachineSystem.cs | 7 + .../Components/DatasetVocalizerComponent.cs | 18 ++ .../Components/VocalizerComponent.cs | 7 + .../VocalizerRequiresPowerComponent.cs | 9 + .../Systems/DatasetVocalizationSystem.cs | 31 +++ .../Systems/VocalizationSystem.cs | 30 ++- Resources/Maps/Nonstations/dm01-entryway.yml | 2 - .../Prototypes/Entities/Mobs/NPCs/silicon.yml | 10 +- .../Structures/Machines/Computers/arcades.yml | 20 +- .../Structures/Machines/fatextractor.yml | 7 +- .../Structures/Machines/smartfridge.yml | 7 +- .../Structures/Machines/vending_machines.yml | 201 +++++++++--------- 14 files changed, 231 insertions(+), 271 deletions(-) delete mode 100644 Content.Server/Advertise/Components/AdvertiseComponent.cs delete mode 100644 Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs create mode 100644 Content.Server/Vocalization/Components/DatasetVocalizerComponent.cs create mode 100644 Content.Server/Vocalization/Components/VocalizerRequiresPowerComponent.cs create mode 100644 Content.Server/Vocalization/Systems/DatasetVocalizationSystem.cs diff --git a/Content.Server/Advertise/Components/AdvertiseComponent.cs b/Content.Server/Advertise/Components/AdvertiseComponent.cs deleted file mode 100644 index 94650234bb..0000000000 --- a/Content.Server/Advertise/Components/AdvertiseComponent.cs +++ /dev/null @@ -1,47 +0,0 @@ -using Content.Server.Advertise.EntitySystems; -using Content.Shared.Dataset; -using Robust.Shared.Prototypes; - -namespace Content.Server.Advertise.Components; - -/// -/// Makes this entity periodically advertise by speaking a randomly selected -/// message from a specified dataset into local chat. -/// -[RegisterComponent, Access(typeof(AdvertiseSystem))] -public sealed partial class AdvertiseComponent : Component -{ - /// - /// Minimum time in seconds to wait before saying a new ad, in seconds. Has to be larger than or equal to 1. - /// - [DataField] - public int MinimumWait { get; private set; } = 8 * 60; - - /// - /// Maximum time in seconds to wait before saying a new ad, in seconds. Has to be larger than or equal - /// to - /// - [DataField] - public int MaximumWait { get; private set; } = 10 * 60; - - /// - /// If true, the delay before the first advertisement (at MapInit) will ignore - /// and instead be rolled between 0 and . This only applies to the initial delay; - /// will be respected after that. - /// - [DataField] - public bool Prewarm = true; - - /// - /// The identifier for the advertisements dataset prototype. - /// - [DataField(required: true)] - public ProtoId Pack { get; private set; } - - /// - /// The next time an advertisement will be said. - /// - [DataField] - public TimeSpan NextAdvertisementTime { get; set; } = TimeSpan.Zero; - -} diff --git a/Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs b/Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs deleted file mode 100644 index 7f2e128183..0000000000 --- a/Content.Server/Advertise/EntitySystems/AdvertiseSystem.cs +++ /dev/null @@ -1,106 +0,0 @@ -using Content.Server.Advertise.Components; -using Content.Server.Chat.Systems; -using Content.Server.Power.Components; -using Content.Shared.VendingMachines; -using Robust.Shared.Prototypes; -using Robust.Shared.Random; -using Robust.Shared.Timing; - -namespace Content.Server.Advertise.EntitySystems; - -public sealed class AdvertiseSystem : EntitySystem -{ - [Dependency] private readonly IPrototypeManager _prototypeManager = default!; - [Dependency] private readonly IRobustRandom _random = default!; - [Dependency] private readonly IGameTiming _gameTiming = default!; - [Dependency] private readonly ChatSystem _chat = default!; - - /// - /// The maximum amount of time between checking if advertisements should be displayed - /// - private readonly TimeSpan _maximumNextCheckDuration = TimeSpan.FromSeconds(15); - - /// - /// The next time the game will check if advertisements should be displayed - /// - private TimeSpan _nextCheckTime = TimeSpan.MinValue; - - public override void Initialize() - { - SubscribeLocalEvent(OnMapInit); - - SubscribeLocalEvent(OnPowerReceiverAttemptAdvertiseEvent); - SubscribeLocalEvent(OnVendingAttemptAdvertiseEvent); - - _nextCheckTime = TimeSpan.MinValue; - } - - private void OnMapInit(EntityUid uid, AdvertiseComponent advert, MapInitEvent args) - { - var prewarm = advert.Prewarm; - RandomizeNextAdvertTime(advert, prewarm); - _nextCheckTime = MathHelper.Min(advert.NextAdvertisementTime, _nextCheckTime); - } - - private void RandomizeNextAdvertTime(AdvertiseComponent advert, bool prewarm = false) - { - var minDuration = prewarm ? 0 : Math.Max(1, advert.MinimumWait); - var maxDuration = Math.Max(minDuration, advert.MaximumWait); - var waitDuration = TimeSpan.FromSeconds(_random.Next(minDuration, maxDuration)); - - advert.NextAdvertisementTime = _gameTiming.CurTime + waitDuration; - } - - public void SayAdvertisement(EntityUid uid, AdvertiseComponent? advert = null) - { - if (!Resolve(uid, ref advert)) - return; - - var attemptEvent = new AttemptAdvertiseEvent(uid); - RaiseLocalEvent(uid, ref attemptEvent); - if (attemptEvent.Cancelled) - return; - - if (_prototypeManager.TryIndex(advert.Pack, out var advertisements)) - _chat.TrySendInGameICMessage(uid, Loc.GetString(_random.Pick(advertisements.Values)), InGameICChatType.Speak, hideChat: true); - } - - public override void Update(float frameTime) - { - var currentGameTime = _gameTiming.CurTime; - if (_nextCheckTime > currentGameTime) - return; - - // _nextCheckTime starts at TimeSpan.MinValue, so this has to SET the value, not just increment it. - _nextCheckTime = currentGameTime + _maximumNextCheckDuration; - - var query = EntityQueryEnumerator(); - while (query.MoveNext(out var uid, out var advert)) - { - if (currentGameTime > advert.NextAdvertisementTime) - { - SayAdvertisement(uid, advert); - // The timer is always refreshed when it expires, to prevent mass advertising (ex: all the vending machines have no power, and get it back at the same time). - RandomizeNextAdvertTime(advert); - } - _nextCheckTime = MathHelper.Min(advert.NextAdvertisementTime, _nextCheckTime); - } - } - - - private static void OnPowerReceiverAttemptAdvertiseEvent(EntityUid uid, ApcPowerReceiverComponent powerReceiver, ref AttemptAdvertiseEvent args) - { - args.Cancelled |= !powerReceiver.Powered; - } - - private static void OnVendingAttemptAdvertiseEvent(EntityUid uid, VendingMachineComponent machine, ref AttemptAdvertiseEvent args) - { - args.Cancelled |= machine.Broken; - } -} - -[ByRefEvent] -public record struct AttemptAdvertiseEvent(EntityUid? Advertiser) -{ - public bool Cancelled = false; -} diff --git a/Content.Server/VendingMachines/VendingMachineSystem.cs b/Content.Server/VendingMachines/VendingMachineSystem.cs index fda8f06820..23a744ddd6 100644 --- a/Content.Server/VendingMachines/VendingMachineSystem.cs +++ b/Content.Server/VendingMachines/VendingMachineSystem.cs @@ -4,6 +4,7 @@ using Content.Server.Cargo.Systems; using Content.Server.Emp; using Content.Server.Power.Components; using Content.Server.Power.EntitySystems; +using Content.Server.Vocalization.Systems; using Content.Shared.Cargo; using Content.Shared.Damage; using Content.Shared.Destructible; @@ -42,6 +43,7 @@ namespace Content.Server.VendingMachines SubscribeLocalEvent(OnDamageChanged); SubscribeLocalEvent(OnVendingPrice); SubscribeLocalEvent(OnEmpPulse); + SubscribeLocalEvent(OnTryVocalize); SubscribeLocalEvent(OnActivatableUIOpenAttempt); @@ -309,5 +311,10 @@ namespace Content.Server.VendingMachines component.NextEmpEject = _timing.CurTime; } } + + private void OnTryVocalize(Entity ent, ref TryVocalizeEvent args) + { + args.Cancelled |= ent.Comp.Broken; + } } } diff --git a/Content.Server/Vocalization/Components/DatasetVocalizerComponent.cs b/Content.Server/Vocalization/Components/DatasetVocalizerComponent.cs new file mode 100644 index 0000000000..c64fe017da --- /dev/null +++ b/Content.Server/Vocalization/Components/DatasetVocalizerComponent.cs @@ -0,0 +1,18 @@ +using Content.Shared.Dataset; +using Robust.Shared.Prototypes; + +namespace Content.Server.Vocalization.Components; + +/// +/// A simple message provider for that randomly selects +/// messages from a . +/// +[RegisterComponent] +public sealed partial class DatasetVocalizerComponent : Component +{ + /// + /// ID of the that will provide messages. + /// + [DataField] + public ProtoId Dataset; +} diff --git a/Content.Server/Vocalization/Components/VocalizerComponent.cs b/Content.Server/Vocalization/Components/VocalizerComponent.cs index 0dfde9751b..f5bb37a335 100644 --- a/Content.Server/Vocalization/Components/VocalizerComponent.cs +++ b/Content.Server/Vocalization/Components/VocalizerComponent.cs @@ -27,4 +27,11 @@ public sealed partial class VocalizerComponent : Component [DataField(customTypeSerializer: typeof(TimeOffsetSerializer))] [AutoPausedField] public TimeSpan NextVocalizeInterval = TimeSpan.Zero; + + /// + /// If true, messages spoken by this vocalizer will not be logged in the chat window + /// and will only be shown as speech bubbles. + /// + [DataField] + public bool HideChat; } diff --git a/Content.Server/Vocalization/Components/VocalizerRequiresPowerComponent.cs b/Content.Server/Vocalization/Components/VocalizerRequiresPowerComponent.cs new file mode 100644 index 0000000000..69de671787 --- /dev/null +++ b/Content.Server/Vocalization/Components/VocalizerRequiresPowerComponent.cs @@ -0,0 +1,9 @@ +namespace Content.Server.Vocalization.Components; + +/// +/// Used in combination with . +/// Blocks any attempts to vocalize if the entity has an +/// and is currently unpowered. +/// +[RegisterComponent] +public sealed partial class VocalizerRequiresPowerComponent : Component; diff --git a/Content.Server/Vocalization/Systems/DatasetVocalizationSystem.cs b/Content.Server/Vocalization/Systems/DatasetVocalizationSystem.cs new file mode 100644 index 0000000000..fcca5605f4 --- /dev/null +++ b/Content.Server/Vocalization/Systems/DatasetVocalizationSystem.cs @@ -0,0 +1,31 @@ +using Content.Server.Vocalization.Components; +using Content.Shared.Random.Helpers; +using Robust.Shared.Prototypes; +using Robust.Shared.Random; + +namespace Content.Server.Vocalization.Systems; + +/// +public sealed class DatasetVocalizationSystem : EntitySystem +{ + [Dependency] private readonly IPrototypeManager _protoMan = default!; + [Dependency] private readonly IRobustRandom _random = default!; + + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnTryVocalize); + } + + private void OnTryVocalize(Entity ent, ref TryVocalizeEvent args) + { + if (args.Handled) + return; + + var dataset = _protoMan.Index(ent.Comp.Dataset); + + args.Message = _random.Pick(dataset); + args.Handled = true; + } +} diff --git a/Content.Server/Vocalization/Systems/VocalizationSystem.cs b/Content.Server/Vocalization/Systems/VocalizationSystem.cs index b0a2e232a4..49dfaf4281 100644 --- a/Content.Server/Vocalization/Systems/VocalizationSystem.cs +++ b/Content.Server/Vocalization/Systems/VocalizationSystem.cs @@ -1,4 +1,5 @@ using Content.Server.Chat.Systems; +using Content.Server.Power.Components; using Content.Server.Vocalization.Components; using Content.Shared.ActionBlocker; using Robust.Shared.Random; @@ -18,6 +19,27 @@ public sealed partial class VocalizationSystem : EntitySystem [Dependency] private readonly IGameTiming _gameTiming = default!; [Dependency] private readonly IRobustRandom _random = default!; + public override void Initialize() + { + base.Initialize(); + + SubscribeLocalEvent(OnMapInit); + SubscribeLocalEvent(OnRequiresPowerTryVocalize); + } + + private void OnMapInit(Entity ent, ref MapInitEvent args) + { + ent.Comp.NextVocalizeInterval = _random.Next(ent.Comp.MinVocalizeInterval, ent.Comp.MaxVocalizeInterval); + } + + private void OnRequiresPowerTryVocalize(Entity ent, ref TryVocalizeEvent args) + { + if (!TryComp(ent, out var receiver)) + return; + + args.Cancelled |= !receiver.Powered; + } + /// /// Try speaking by raising a TryVocalizeEvent /// This event is passed to systems adding a message to it and setting it to handled @@ -27,6 +49,10 @@ public sealed partial class VocalizationSystem : EntitySystem var tryVocalizeEvent = new TryVocalizeEvent(); RaiseLocalEvent(entity.Owner, ref tryVocalizeEvent); + // If the event was cancelled, don't speak + if (tryVocalizeEvent.Cancelled) + return; + // if the event was never handled, return // this happens if there are no components that trigger systems to add a message to this event if (!tryVocalizeEvent.Handled) @@ -60,7 +86,7 @@ public sealed partial class VocalizationSystem : EntitySystem return; // send the message - _chat.TrySendInGameICMessage(entity, message, InGameICChatType.Speak, ChatTransmitRange.Normal); + _chat.TrySendInGameICMessage(entity, message, InGameICChatType.Speak, entity.Comp.HideChat ? ChatTransmitRange.HideChat : ChatTransmitRange.Normal); } public override void Update(float frameTime) @@ -99,7 +125,7 @@ public sealed partial class VocalizationSystem : EntitySystem /// Message to send, this is null when the event is just fired and should be set by a system /// Whether the message was handled by a system [ByRefEvent] -public record struct TryVocalizeEvent(string? Message = null, bool Handled = false); +public record struct TryVocalizeEvent(string? Message = null, bool Handled = false, bool Cancelled = false); /// /// Fired when the entity wants to vocalize and has a message. Allows for interception by other systems if the diff --git a/Resources/Maps/Nonstations/dm01-entryway.yml b/Resources/Maps/Nonstations/dm01-entryway.yml index bb252e35ab..2f15189a67 100644 --- a/Resources/Maps/Nonstations/dm01-entryway.yml +++ b/Resources/Maps/Nonstations/dm01-entryway.yml @@ -3958,8 +3958,6 @@ entities: - type: Transform pos: 8.5,27.5 parent: 2 - - type: Advertise - nextAdvertisementTime: 6277.3942716 - proto: WallPlastitaniumDiagonalIndestructible entities: - uid: 171 diff --git a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml index e0518be3b2..382de8e085 100644 --- a/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml +++ b/Resources/Prototypes/Entities/Mobs/NPCs/silicon.yml @@ -159,8 +159,9 @@ interactFailureString: petting-failure-firebot interactSuccessSound: path: /Audio/Ambience/Objects/periodic_beep.ogg - - type: Advertise - pack: FirebotAd + - type: Vocalizer + - type: DatasetVocalizer + dataset: FirebotAd - type: entity parent: MobSiliconBase @@ -355,8 +356,9 @@ interactFailureString: petting-failure-medibot interactSuccessSound: path: /Audio/Ambience/Objects/periodic_beep.ogg - - type: Advertise - pack: MedibotAds + - type: Vocalizer + - type: DatasetVocalizer + dataset: MedibotAds - type: Inventory templateId: medibot - type: DoAfter diff --git a/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml b/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml index d57e1c4bf8..84df160258 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/Computers/arcades.yml @@ -170,10 +170,12 @@ type: WiresBoundUserInterface - type: Computer board: SpaceVillainArcadeComputerCircuitboard - - type: Advertise - pack: SpaceVillainAds - minimumWait: 60 # Arcades are noisy - maximumWait: 240 + - type: Vocalizer + minVocalizeInterval: 1m # Arcades are noisy + maxVocalizeInterval: 4m + hideChat: true + - type: DatasetVocalizer + dataset: SpaceVillainAds - type: SpeakOnUIClosed pack: SpaceVillainGoodbyes @@ -215,9 +217,11 @@ type: WiresBoundUserInterface - type: Computer board: BlockGameArcadeComputerCircuitboard - - type: Advertise - pack: BlockGameAds - minimumWait: 60 # Arcades are noisy - maximumWait: 240 + - type: Vocalizer + minVocalizeInterval: 1m # Arcades are noisy + maxVocalizeInterval: 4m + hideChat: true + - type: DatasetVocalizer + dataset: BlockGameAds - type: SpeakOnUIClosed pack: BlockGameGoodbyes diff --git a/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml b/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml index 770a17a8ff..c4b26e043b 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/fatextractor.yml @@ -101,8 +101,11 @@ - type: Appearance - type: Speech speechVerb: Robotic - - type: Advertise - pack: FatExtractorFacts + - type: Vocalizer + hideChat: true + - type: VocalizerRequiresPower + - type: DatasetVocalizer + dataset: FatExtractorFacts - type: StaticPrice price: 1000 - type: ResistLocker diff --git a/Resources/Prototypes/Entities/Structures/Machines/smartfridge.yml b/Resources/Prototypes/Entities/Structures/Machines/smartfridge.yml index 748b3426c4..8ea6fee938 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/smartfridge.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/smartfridge.yml @@ -5,8 +5,11 @@ description: A refrigerated storage unit for keeping items cold and fresh. components: - type: StationAiWhitelist - - type: Advertise - pack: SmartFridgeAds + - type: Vocalizer + hideChat: true + - type: VocalizerRequiresPower + - type: DatasetVocalizer + dataset: SmartFridgeAds - type: Speech - type: Appearance - type: Sprite diff --git a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml index 54cb396fdc..12ce780ff7 100644 --- a/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml +++ b/Resources/Prototypes/Entities/Structures/Machines/vending_machines.yml @@ -73,6 +73,11 @@ - type: Speech speechVerb: Robotic speechSounds: Vending + - type: Vocalizer + minVocalizeInterval: 8m + maxVocalizeInterval: 10m + hideChat: true + - type: VocalizerRequiresPower - type: SpookySpeaker messageSet: SpookySpeakerMessagesGeneric speakChance: 0.2 @@ -126,8 +131,8 @@ layer: - MachineLayer density: 190 - - type: Advertise - pack: CondimentVendAds + - type: DatasetVocalizer + dataset: CondimentVendAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Transform @@ -144,8 +149,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: AmmoVendAds + - type: DatasetVocalizer + dataset: CondimentVendAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -172,8 +177,8 @@ normalState: normal-unshaded denyState: deny-unshaded loopDeny: false - - type: Advertise - pack: BoozeOMatAds + - type: DatasetVocalizer + dataset: BoozeOMatAds - type: SpeakOnUIClosed pack: BoozeOMatGoodbyes - type: Sprite @@ -206,8 +211,8 @@ normalState: normal-unshaded denyState: deny-unshaded loopDeny: false - - type: Advertise - pack: BruiseOMatAds + - type: DatasetVocalizer + dataset: BruiseOMatAds - type: SpeakOnUIClosed pack: BruiseOMatGoodbyes - type: Sprite @@ -269,8 +274,8 @@ brokenState: broken normalState: normal-unshaded ejectState: eject-unshaded - - type: Advertise - pack: ChefvendAds + - type: DatasetVocalizer + dataset: ChefvendAds - type: SpeakOnUIClosed pack: ChefvendGoodbyes - type: Sprite @@ -305,8 +310,8 @@ normalState: normal-unshaded ejectState: eject-unshaded denyState: deny-unshaded - - type: Advertise - pack: CigaretteMachineAds + - type: DatasetVocalizer + dataset: CigaretteMachineAds - type: SpeakOnUIClosed pack: CigaretteMachineGoodbyes - type: Sprite @@ -332,8 +337,8 @@ brokenState: broken normalState: normal-unshaded denyState: deny-unshaded - - type: Advertise - pack: ClothesMateAds + - type: DatasetVocalizer + dataset: ClothesMateAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -363,8 +368,8 @@ brokenState: broken normalState: normal-unshaded denyState: deny-unshaded - - type: Advertise - pack: ClothesMateAds + - type: DatasetVocalizer + dataset: ClothesMateAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -401,8 +406,8 @@ ejectDelay: 5 soundVend: /Audio/Machines/machine_vend_hot_drink.ogg initialStockQuality: 0.33 - - type: Advertise - pack: HotDrinksMachineAds + - type: DatasetVocalizer + dataset: HotDrinksMachineAds - type: SpeakOnUIClosed pack: HotDrinksMachineGoodbyes - type: Sprite @@ -440,8 +445,8 @@ denyState: deny-unshaded ejectDelay: 1.9 initialStockQuality: 0.33 - - type: Advertise - pack: RobustSoftdrinksAds + - type: DatasetVocalizer + dataset: RobustSoftdrinksAds - type: SpeakOnUIClosed pack: RobustSoftdrinksGoodbyes - type: Sprite @@ -585,8 +590,8 @@ denyState: deny-unshaded ejectDelay: 1.9 initialStockQuality: 0.33 - - type: Advertise - pack: RobustSoftdrinksAds + - type: DatasetVocalizer + dataset: RobustSoftdrinksAds - type: Sprite sprite: Structures/Machines/VendingMachines/shamblersjuice.rsi layers: @@ -619,8 +624,8 @@ denyState: deny-unshaded ejectDelay: 1.9 initialStockQuality: 0.33 - - type: Advertise - pack: RobustSoftdrinksAds + - type: DatasetVocalizer + dataset: RobustSoftdrinksAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -655,8 +660,8 @@ denyState: deny-unshaded ejectDelay: 1.9 initialStockQuality: 0.33 - - type: Advertise - pack: DrGibbAds + - type: DatasetVocalizer + dataset: DrGibbAds - type: SpeakOnUIClosed pack: DrGibbGoodbyes - type: Sprite @@ -701,8 +706,8 @@ denyState: deny-unshaded ejectDelay: 1.9 initialStockQuality: 0.33 - - type: Advertise - pack: SmiteAds + - type: DatasetVocalizer + dataset: SmiteAds - type: SpeakOnUIClosed pack: SmiteGoodbyes - type: PointLight @@ -722,8 +727,8 @@ brokenState: broken normalState: normal-unshaded ejectState: eject-unshaded - - type: Advertise - pack: DinnerwareAds + - type: DatasetVocalizer + dataset: DinnerwareAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -754,8 +759,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: MagiVendAds + - type: DatasetVocalizer + dataset: MagiVendAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -787,8 +792,8 @@ brokenState: broken normalState: normal-unshaded initialStockQuality: 0.33 - - type: Advertise - pack: DiscountDansAds + - type: DatasetVocalizer + dataset: DiscountDansAds - type: SpeakOnUIClosed pack: DiscountDansGoodbyes - type: Sprite @@ -850,8 +855,8 @@ ejectState: eject-unshaded denyState: deny-unshaded ejectDelay: 0.6 - - type: Advertise - pack: NanoMedAds + - type: DatasetVocalizer + dataset: NanoMedAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -887,8 +892,8 @@ normalState: normal-unshaded ejectState: eject-unshaded denyState: deny-unshaded - - type: Advertise - pack: NutriMaxAds + - type: DatasetVocalizer + dataset: NutriMaxAds - type: SpeakOnUIClosed pack: NutriMaxGoodbyes - type: Sprite @@ -921,8 +926,8 @@ normalState: normal-unshaded ejectState: eject-unshaded denyState: deny-unshaded - - type: Advertise - pack: SecTechAds + - type: DatasetVocalizer + dataset: SecTechAds - type: SpeakOnUIClosed pack: SecTechGoodbyes - type: Sprite @@ -960,8 +965,8 @@ normalState: normal-unshaded ejectState: eject-unshaded denyState: deny-unshaded - - type: Advertise - pack: MegaSeedAds + - type: DatasetVocalizer + dataset: MegaSeedAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1003,8 +1008,8 @@ ejectState: eject-unshaded denyState: deny-unshaded initialStockQuality: 0.33 - - type: Advertise - pack: GetmoreChocolateCorpAds + - type: DatasetVocalizer + dataset: GetmoreChocolateCorpAds - type: SpeakOnUIClosed pack: GetmoreChocolateCorpGoodbyes - type: Sprite @@ -1148,8 +1153,8 @@ ejectState: eject-unshaded denyState: deny-unshaded initialStockQuality: 0.33 - - type: Advertise - pack: BodaAds + - type: DatasetVocalizer + dataset: BodaAds - type: SpeakOnUIClosed pack: BodaGoodbyes - type: Sprite @@ -1182,8 +1187,8 @@ ejectState: eject-unshaded denyState: deny-unshaded screenState: screen - - type: Advertise - pack: AutoDrobeAds + - type: DatasetVocalizer + dataset: AutoDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1217,8 +1222,8 @@ normalState: normal-unshaded ejectState: eject-unshaded denyState: deny-unshaded - - type: Advertise - pack: VendomatAds + - type: DatasetVocalizer + dataset: VendomatAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1249,8 +1254,8 @@ normalState: normal-unshaded ejectState: eject-unshaded denyState: deny-unshaded - - type: Advertise - pack: VendomatAds + - type: DatasetVocalizer + dataset: VendomatAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1314,8 +1319,8 @@ normalState: normal-unshaded ejectState: eject-unshaded ejectDelay: 1.8 - - type: Advertise - pack: GoodCleanFunAds + - type: DatasetVocalizer + dataset: GoodCleanFunAds - type: SpeakOnUIClosed pack: GoodCleanFunGoodbyes - type: Sprite @@ -1347,8 +1352,8 @@ brokenState: broken normalState: normal-unshaded initialStockQuality: 0.33 - - type: Advertise - pack: ChangAds + - type: DatasetVocalizer + dataset: ChangAds - type: SpeakOnUIClosed pack: ChangGoodbyes - type: Sprite @@ -1412,8 +1417,8 @@ brokenState: broken normalState: normal-unshaded initialStockQuality: 0.33 - - type: Advertise - pack: DonutAds + - type: DatasetVocalizer + dataset: DonutAds - type: SpeakOnUIClosed pack: DonutGoodbyes - type: Sprite @@ -1497,8 +1502,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: HyDrobeAds + - type: DatasetVocalizer + dataset: HyDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1529,8 +1534,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: LawDrobeAds + - type: DatasetVocalizer + dataset: LawDrobeAds - type: SpeakOnUIClosed pack: LawDrobeGoodbyes - type: Sprite @@ -1557,8 +1562,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: SecDrobeAds + - type: DatasetVocalizer + dataset: SecDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1589,8 +1594,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: BarDrobeAds + - type: DatasetVocalizer + dataset: BarDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1645,8 +1650,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: CargoDrobeAds + - type: DatasetVocalizer + dataset: CargoDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1677,8 +1682,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: MediDrobeAds + - type: DatasetVocalizer + dataset: MediDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1705,8 +1710,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: ChemDrobeAds + - type: DatasetVocalizer + dataset: ChemDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1733,8 +1738,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: CuraDrobeAds + - type: DatasetVocalizer + dataset: CuraDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1761,8 +1766,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: AtmosDrobeAds + - type: DatasetVocalizer + dataset: AtmosDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1793,8 +1798,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: EngiDrobeAds + - type: DatasetVocalizer + dataset: EngiDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1825,8 +1830,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: ChefDrobeAds + - type: DatasetVocalizer + dataset: ChefDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1853,8 +1858,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: DetDrobeAds + - type: DatasetVocalizer + dataset: DetDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1881,8 +1886,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: JaniDrobeAds + - type: DatasetVocalizer + dataset: JaniDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1913,8 +1918,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: SciDrobeAds + - type: DatasetVocalizer + dataset: SciDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -1941,8 +1946,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: SyndieDrobeAds + - type: DatasetVocalizer + dataset: SyndieDrobeAds - type: SpeakOnUIClosed pack: SyndieDrobeGoodbyes - type: Sprite @@ -1973,8 +1978,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: RoboDrobeAds + - type: DatasetVocalizer + dataset: RoboDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -2001,8 +2006,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: GeneDrobeAds + - type: DatasetVocalizer + dataset: GeneDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -2029,8 +2034,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: ViroDrobeAds + - type: DatasetVocalizer + dataset: ViroDrobeAds - type: SpeakOnUIClosed pack: GenericVendGoodbyes - type: Sprite @@ -2105,8 +2110,8 @@ radius: 1.5 energy: 1.6 color: "#3c5eb5" - - type: Advertise - pack: HappyHonkAds + - type: DatasetVocalizer + dataset: HappyHonkAds - type: SpeakOnUIClosed pack: HappyHonkGoodbyes - type: AccessReader @@ -2125,8 +2130,8 @@ offState: off brokenState: broken normalState: normal-unshaded - - type: Advertise - pack: PrideDrobeAds + - type: DatasetVocalizer + dataset: PrideDrobeAds - type: SpeakOnUIClosed pack: PrideDrobeGoodbyes - type: Speech