diff --git a/OpenRA.Game/OpenRA.Game.csproj b/OpenRA.Game/OpenRA.Game.csproj index a1e1d691a3..b211f9c12c 100644 --- a/OpenRA.Game/OpenRA.Game.csproj +++ b/OpenRA.Game/OpenRA.Game.csproj @@ -179,6 +179,7 @@ + diff --git a/OpenRA.Game/Selection.cs b/OpenRA.Game/Selection.cs index 7e86b519f0..2700aee20a 100644 --- a/OpenRA.Game/Selection.cs +++ b/OpenRA.Game/Selection.cs @@ -57,9 +57,9 @@ namespace OpenRA } } - var voicedUnit = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.IsInWorld && a.HasVoices()); - if (voicedUnit != null) - Sound.PlayVoice("Select", voicedUnit, voicedUnit.Owner.Country.Race); + var voicedActor = actors.FirstOrDefault(a => a.Owner == world.LocalPlayer && a.IsInWorld && a.HasTrait()); + if (voicedActor != null) + voicedActor.PlayVoice("Select"); foreach (var a in newSelection) foreach (var sel in a.TraitsImplementing()) diff --git a/OpenRA.Game/Sound/Sound.cs b/OpenRA.Game/Sound/Sound.cs index 8654ee2334..5af665c5d7 100644 --- a/OpenRA.Game/Sound/Sound.cs +++ b/OpenRA.Game/Sound/Sound.cs @@ -300,7 +300,7 @@ namespace OpenRA } // Returns true if played successfully - public static bool PlayPredefined(Ruleset ruleset, Player p, Actor voicedUnit, string type, string definition, string variant, + public static bool PlayPredefined(Ruleset ruleset, Player p, Actor voicedActor, string type, string definition, string variant, bool relative, WPos pos, float volumeModifier, bool attenuateVolume) { if (ruleset == null) @@ -312,17 +312,17 @@ namespace OpenRA if (ruleset.Voices == null || ruleset.Notifications == null) return false; - var rules = (voicedUnit != null) ? ruleset.Voices[type] : ruleset.Notifications[type]; + var rules = (voicedActor != null) ? ruleset.Voices[type] : ruleset.Notifications[type]; if (rules == null) return false; - var id = voicedUnit != null ? voicedUnit.ActorID : 0; + var id = voicedActor != null ? voicedActor.ActorID : 0; string clip; var suffix = rules.DefaultVariant; var prefix = rules.DefaultPrefix; - if (voicedUnit != null) + if (voicedActor != null) { if (!rules.VoicePools.Value.ContainsKey("Attack")) rules.VoicePools.Value.Add("Attack", rules.VoicePools.Value["Move"]); @@ -364,32 +364,6 @@ namespace OpenRA return true; } - public static bool PlayVoice(string phrase, Actor voicedUnit, string variant) - { - if (voicedUnit == null || phrase == null) - return false; - - var mi = voicedUnit.Info.Traits.GetOrDefault(); - if (mi == null || mi.Voice == null) - return false; - - var type = mi.Voice.ToLowerInvariant(); - return PlayPredefined(voicedUnit.World.Map.Rules, null, voicedUnit, type, phrase, variant, true, WPos.Zero, 1f, true); - } - - public static bool PlayVoiceLocal(string phrase, Actor voicedUnit, string variant, WPos pos, float volume) - { - if (voicedUnit == null || phrase == null) - return false; - - var mi = voicedUnit.Info.Traits.GetOrDefault(); - if (mi == null || mi.Voice == null) - return false; - - var type = mi.Voice.ToLowerInvariant(); - return PlayPredefined(voicedUnit.World.Map.Rules, null, voicedUnit, type, phrase, variant, false, pos, volume, true); - } - public static bool PlayNotification(Ruleset rules, Player player, string type, string notification, string variant) { if (rules == null) diff --git a/OpenRA.Game/Traits/Selectable.cs b/OpenRA.Game/Traits/Selectable.cs index 1c05250734..5e23b4cab6 100644 --- a/OpenRA.Game/Traits/Selectable.cs +++ b/OpenRA.Game/Traits/Selectable.cs @@ -20,7 +20,6 @@ namespace OpenRA.Traits public readonly bool Selectable = true; public readonly int Priority = 10; public readonly int[] Bounds = null; - [VoiceReference] public readonly string Voice = null; public object Create(ActorInitializer init) { return new Selectable(init.Self, this); } } diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 301d162542..e5c7990c1a 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -109,6 +109,14 @@ namespace OpenRA.Traits public interface ISeedableResource { void Seed(Actor self); } + public interface IVoiced + { + string VoiceSet { get; } + bool PlayVoice(Actor self, string phrase, string variant); + bool PlayVoiceLocal(Actor self, string phrase, string variant, float volume); + bool HasVoice(Actor self, string voice); + } + public interface IDemolishableInfo { bool IsValidTarget(ActorInfo actorInfo, Actor saboteur); } public interface IDemolishable { diff --git a/OpenRA.Game/VoiceExts.cs b/OpenRA.Game/VoiceExts.cs new file mode 100644 index 0000000000..c63d7a4d69 --- /dev/null +++ b/OpenRA.Game/VoiceExts.cs @@ -0,0 +1,75 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Drawing; +using System.Linq; +using OpenRA.Traits; + +namespace OpenRA +{ + public static class VoiceExts + { + public static void PlayVoice(this Actor self, string phrase) + { + if (phrase == null) + return; + + foreach (var voiced in self.TraitsImplementing()) + { + if (string.IsNullOrEmpty(voiced.VoiceSet)) + return; + + voiced.PlayVoice(self, phrase, self.Owner.Country.Race); + } + } + + public static void PlayVoiceLocal(this Actor self, string phrase, float volume) + { + if (phrase == null) + return; + + foreach (var voiced in self.TraitsImplementing()) + { + if (string.IsNullOrEmpty(voiced.VoiceSet)) + return; + + voiced.PlayVoiceLocal(self, phrase, self.Owner.Country.Race, volume); + } + } + + public static bool HasVoice(this Actor self, string voice) + { + return self.TraitsImplementing().Any(x => x.HasVoice(self, voice)); + } + + public static void PlayVoiceForOrders(this World w, Order[] orders) + { + // Find an actor with a phrase to say + foreach (var o in orders) + { + if (o == null) + continue; + + var orderSubject = o.Subject; + if (orderSubject.Destroyed) + continue; + + foreach (var voice in orderSubject.TraitsImplementing()) + foreach (var v in orderSubject.TraitsImplementing()) + { + if (voice.PlayVoice(orderSubject, v.VoicePhraseForOrder(orderSubject, o), + orderSubject.Owner.Country.Race)) + return; + } + } + } + } +} diff --git a/OpenRA.Game/WorldUtils.cs b/OpenRA.Game/WorldUtils.cs index 868273632d..d3cd04cda8 100644 --- a/OpenRA.Game/WorldUtils.cs +++ b/OpenRA.Game/WorldUtils.cs @@ -42,44 +42,6 @@ namespace OpenRA } } - public static bool HasVoices(this Actor a) - { - var selectable = a.Info.Traits.GetOrDefault(); - return selectable != null && selectable.Voice != null; - } - - public static bool HasVoice(this Actor a, string voice) - { - var v = GetVoices(a); - return v != null && v.Voices.ContainsKey(voice); - } - - public static SoundInfo GetVoices(this Actor a) - { - var selectable = a.Info.Traits.GetOrDefault(); - if (selectable == null) return null; - var v = selectable.Voice; - return (v == null) ? null : a.World.Map.Rules.Voices[v.ToLowerInvariant()]; - } - - public static void PlayVoiceForOrders(this World w, Order[] orders) - { - // Find an actor with a phrase to say - foreach (var o in orders) - { - if (o == null) - continue; - - if (o.Subject.Destroyed) - continue; - - foreach (var v in o.Subject.TraitsImplementing()) - if (Sound.PlayVoice(v.VoicePhraseForOrder(o.Subject, o), - o.Subject, o.Subject.Owner.Country.Race)) - return; - } - } - public static void DoTimed(this IEnumerable e, Action a, string text) { // Note - manual enumeration here for performance due to high call volume. diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index cc1b29a043..ed5dce8e10 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -443,6 +443,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/Cargo.cs b/OpenRA.Mods.Common/Traits/Cargo.cs index 5c86323984..e501df1acf 100644 --- a/OpenRA.Mods.Common/Traits/Cargo.cs +++ b/OpenRA.Mods.Common/Traits/Cargo.cs @@ -39,6 +39,9 @@ namespace OpenRA.Mods.Common.Traits [Desc("Terrain types that this actor is allowed to eject actors onto. Leave empty for all terrain types.")] public readonly string[] UnloadTerrainTypes = { }; + [Desc("Voice to play when ordered to unload the passengers.")] + public readonly string UnloadVoice = "Unload"; + [Desc("Which direction the passenger will face (relative to the transport) when unloading.")] public readonly int PassengerFacing = 128; @@ -204,10 +207,10 @@ namespace OpenRA.Mods.Common.Traits public string VoicePhraseForOrder(Actor self, Order order) { - if (order.OrderString != "Unload" || IsEmpty(self)) + if (order.OrderString != "Unload" || IsEmpty(self) || !self.HasVoice(Info.UnloadVoice)) return null; - return self.HasVoice("Unload") ? "Unload" : "Move"; + return Info.UnloadVoice; } public bool MoveDisabled(Actor self) { return reserves.Any(); } diff --git a/OpenRA.Mods.Common/Traits/Sound/AnnounceOnBuild.cs b/OpenRA.Mods.Common/Traits/Sound/AnnounceOnBuild.cs index 1aee77e138..f2fb745b6f 100644 --- a/OpenRA.Mods.Common/Traits/Sound/AnnounceOnBuild.cs +++ b/OpenRA.Mods.Common/Traits/Sound/AnnounceOnBuild.cs @@ -13,13 +13,26 @@ using OpenRA.Traits; namespace OpenRA.Mods.Common.Traits { [Desc("Play the Build voice of this actor when trained.")] - public class AnnounceOnBuildInfo : TraitInfo { } + public class AnnounceOnBuildInfo : ITraitInfo + { + [Desc("Voice to use when built/trained.")] + public readonly string BuildVoice = "Build"; + + public object Create(ActorInitializer init) { return new AnnounceOnBuild(init.Self, this); } + } public class AnnounceOnBuild : INotifyBuildComplete { + readonly AnnounceOnBuildInfo info; + + public AnnounceOnBuild(Actor self, AnnounceOnBuildInfo info) + { + this.info = info; + } + public void BuildingComplete(Actor self) { - Sound.PlayVoice("Build", self, self.Owner.Country.Race); + self.PlayVoice(info.BuildVoice); } } } diff --git a/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs b/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs index e5da13aef1..64713a8b82 100644 --- a/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs +++ b/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs @@ -18,6 +18,9 @@ namespace OpenRA.Mods.Common.Traits [Desc("Minimum duration (in seconds) between sound events.")] public readonly int Interval = 5; + [Desc("Voice to use when killing something.")] + public readonly string KillVoice = "Kill"; + public object Create(ActorInitializer init) { return new AnnounceOnKill(init.Self, this); } } @@ -39,7 +42,7 @@ namespace OpenRA.Mods.Common.Traits if (e.DamageState == DamageState.Dead && damaged != e.Attacker) { if (self.World.WorldTick - lastAnnounce > info.Interval * 25) - Sound.PlayVoice("Kill", self, self.Owner.Country.Race); + self.PlayVoice(info.KillVoice); lastAnnounce = self.World.WorldTick; } diff --git a/OpenRA.Mods.Common/Traits/Sound/DeathSounds.cs b/OpenRA.Mods.Common/Traits/Sound/DeathSounds.cs index 0f150d53d3..1f590806ed 100644 --- a/OpenRA.Mods.Common/Traits/Sound/DeathSounds.cs +++ b/OpenRA.Mods.Common/Traits/Sound/DeathSounds.cs @@ -40,11 +40,9 @@ namespace OpenRA.Mods.Common.Traits if (e.Warhead == null) return; - var cp = self.CenterPosition; - - if (info.DeathTypes.Contains(e.Warhead.DeathType) || - (!info.DeathTypes.Any() && !self.Info.Traits.WithInterface().Any(dsi => dsi.DeathTypes.Contains(e.Warhead.DeathType)))) - Sound.PlayVoiceLocal(info.DeathSound, self, self.Owner.Country.Race, cp, info.VolumeMultiplier); + if (info.DeathTypes.Contains(e.Warhead.DeathType) || (!info.DeathTypes.Any() && + !self.Info.Traits.WithInterface().Any(dsi => dsi.DeathTypes.Contains(e.Warhead.DeathType)))) + self.PlayVoiceLocal(info.DeathSound, info.VolumeMultiplier); } } } \ No newline at end of file diff --git a/OpenRA.Mods.Common/Traits/Voiced.cs b/OpenRA.Mods.Common/Traits/Voiced.cs new file mode 100644 index 0000000000..e6359aabe2 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/Voiced.cs @@ -0,0 +1,75 @@ +#region Copyright & License Information +/* + * Copyright 2007-2015 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation. For more information, + * see COPYING. + */ +#endregion + +using System.Collections.Generic; +using System.Linq; +using OpenRA.GameRules; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + [Desc("This actor has a voice.")] + public class VoicedInfo : ITraitInfo + { + [Desc("Which voice set to use.")] + [VoiceReference] public readonly string VoiceSet = null; + + [Desc("Multiply volume with this factor.")] + public readonly float Volume = 1f; + + public object Create(ActorInitializer init) { return new Voiced(init.Self, this); } + } + + public class Voiced : IVoiced + { + public readonly VoicedInfo Info; + + public Voiced(Actor self, VoicedInfo info) + { + Info = info; + } + + public string VoiceSet { get { return Info.VoiceSet; } } + + public bool PlayVoice(Actor self, string phrase, string variant) + { + if (phrase == null) + return false; + + if (string.IsNullOrEmpty(Info.VoiceSet)) + return false; + + var type = Info.VoiceSet.ToLowerInvariant(); + var volume = Info.Volume; + return Sound.PlayPredefined(self.World.Map.Rules, null, self, type, phrase, variant, true, WPos.Zero, volume, true); + } + + public bool PlayVoiceLocal(Actor self, string phrase, string variant, float volume) + { + if (phrase == null) + return false; + + if (string.IsNullOrEmpty(Info.VoiceSet)) + return false; + + var type = Info.VoiceSet.ToLowerInvariant(); + return Sound.PlayPredefined(self.World.Map.Rules, null, self, type, phrase, variant, false, self.CenterPosition, volume, true); + } + + public bool HasVoice(Actor self, string voice) + { + if (string.IsNullOrEmpty(Info.VoiceSet)) + return false; + + var voices = self.World.Map.Rules.Voices[Info.VoiceSet.ToLowerInvariant()]; + return voices != null && voices.Voices.ContainsKey(voice); + } + } +} diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index 38ddd21285..1133847829 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -943,6 +943,28 @@ namespace OpenRA.Mods.Common.UtilityCommands node.Key = node.Key.Replace("ProvidesCustomPrerequisite", "ProvidesPrerequisite"); } + if (engineVersion < 20150509) + { + if (depth == 0 && node.Value.Nodes.Exists(n => n.Key == "Selectable")) + { + var selectable = node.Value.Nodes.FirstOrDefault(n => n.Key == "Selectable"); + var selectableNodes = selectable.Value.Nodes; + var voice = selectableNodes.FirstOrDefault(n => n.Key == "Voice"); + var selectableVoice = voice != null ? FieldLoader.GetValue("Voice", voice.Value.Value) : ""; + + if (voice != null) + { + node.Value.Nodes.Add(new MiniYamlNode("Voiced", "", new List + { + new MiniYamlNode("VoiceSet", selectableVoice), + })); + } + } + + if (node.Key.StartsWith("Selectable")) + node.Value.Nodes.RemoveAll(p => p.Key == "Voice"); + } + UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); } } diff --git a/mods/cnc/audio/voices.yaml b/mods/cnc/audio/voices.yaml index b0045e5624..c69770bf45 100644 --- a/mods/cnc/audio/voices.yaml +++ b/mods/cnc/audio/voices.yaml @@ -18,6 +18,7 @@ VehicleVoice: Voices: Select: vehic1,yessir1,report1,await1,unit1 Move: ackno,affirm1,movout1 + Unload: movout1 CivilianMaleVoice: Voices: diff --git a/mods/cnc/rules/civilian.yaml b/mods/cnc/rules/civilian.yaml index 0167e02dab..4cb3b82688 100644 --- a/mods/cnc/rules/civilian.yaml +++ b/mods/cnc/rules/civilian.yaml @@ -381,12 +381,14 @@ BRIDGEHUT: C1: Inherits: ^CivInfantry Selectable: - Voice: CivilianMaleVoice + Voiced: + VoiceSet: CivilianMaleVoice C2: Inherits: ^CivInfantry Selectable: - Voice: CivilianFemaleVoice + Voiced: + VoiceSet: CivilianFemaleVoice C3: Inherits: ^CivInfantry @@ -394,7 +396,8 @@ C3: C4: Inherits: ^CivInfantry Selectable: - Voice: CivilianFemaleVoice + Voiced: + VoiceSet: CivilianFemaleVoice C5: Inherits: ^CivInfantry @@ -402,7 +405,8 @@ C5: C6: Inherits: ^CivInfantry Selectable: - Voice: CivilianFemaleVoice + Voiced: + VoiceSet: CivilianFemaleVoice C7: Inherits: ^CivInfantry @@ -410,7 +414,8 @@ C7: C8: Inherits: ^CivInfantry Selectable: - Voice: CivilianFemaleVoice + Voiced: + VoiceSet: CivilianFemaleVoice C9: Inherits: ^CivInfantry @@ -418,7 +423,8 @@ C9: C10: Inherits: ^CivInfantry Selectable: - Voice: CivilianFemaleVoice + Voiced: + VoiceSet: CivilianFemaleVoice VICE: AppearsOnRadar: @@ -439,7 +445,6 @@ VICE: BlueTiberium: 100 Beach: 60 Selectable: - Voice: DinoVoice TargetableUnit: TargetTypes: Ground AutoTarget: @@ -472,4 +477,6 @@ VICE: QuantizedFacings: 8 PoisonedByTiberium: Weapon: Heal + Voiced: + VoiceSet: DinoVoice diff --git a/mods/cnc/rules/defaults.yaml b/mods/cnc/rules/defaults.yaml index 26b118a5f0..80cf6acf8a 100644 --- a/mods/cnc/rules/defaults.yaml +++ b/mods/cnc/rules/defaults.yaml @@ -12,7 +12,6 @@ ROT: 5 SelectionDecorations: Selectable: - Voice: VehicleVoice TargetableUnit: TargetTypes: Ground, Vehicle Repairable: @@ -51,6 +50,8 @@ UpgradeMinEnabledLevel: 1 UpgradeManager: MustBeDestroyed: + Voiced: + VoiceSet: VehicleVoice ^Tank: AppearsOnRadar: @@ -66,7 +67,6 @@ ROT: 5 SelectionDecorations: Selectable: - Voice: VehicleVoice TargetableUnit: TargetTypes: Ground, Vehicle Repairable: @@ -108,6 +108,8 @@ UpgradeMinEnabledLevel: 1 UpgradeManager: MustBeDestroyed: + Voiced: + VoiceSet: VehicleVoice ^Helicopter: AppearsOnRadar: @@ -117,7 +119,6 @@ GroundedTargetTypes: Ground SelectionDecorations: Selectable: - Voice: VehicleVoice Helicopter: RepairBuildings: hpad RearmBuildings: @@ -152,6 +153,8 @@ WithShadow: Hovers: MustBeDestroyed: + Voiced: + VoiceSet: VehicleVoice ^Infantry: AppearsOnRadar: @@ -177,7 +180,6 @@ Beach: 80 SelectionDecorations: Selectable: - Voice: GenericVoice TargetableUnit: TargetTypes: Ground, Infantry TakeCover: @@ -241,6 +243,8 @@ UpgradeMinEnabledLevel: 1 UpgradeManager: MustBeDestroyed: + Voiced: + VoiceSet: GenericVoice ^CivInfantry: Inherits: ^Infantry @@ -249,7 +253,6 @@ AppearsOnRadar: SelectionDecorations: Selectable: - Voice: CivilianMaleVoice Bounds: 12,17,0,-9 Valued: Cost: 70 @@ -271,6 +274,8 @@ ScaredyCat: Crushable: CrushSound: squish2.aud + Voiced: + VoiceSet: CivilianMaleVoice ^DINO: AppearsOnRadar: @@ -299,7 +304,6 @@ BlueTiberium: 70 Beach: 80 Selectable: - Voice: DinoVoice TargetableUnit: TargetTypes: Ground, Infantry HiddenUnderFog: @@ -321,13 +325,14 @@ DeathSounds: RenderSprites: Palette: terrain + Voiced: + VoiceSet: DinoVoice ^Plane: AppearsOnRadar: UseLocation: yes SelectionDecorations: Selectable: - Voice: GenericVoice TargetableUnit: TargetTypes: Air HiddenUnderFog: @@ -350,6 +355,8 @@ UpgradeMinEnabledLevel: 1 UpgradeManager: WithShadow: + Voiced: + VoiceSet: GenericVoice ^Ship: AppearsOnRadar: @@ -359,7 +366,6 @@ Water: 100 SelectionDecorations: Selectable: - Voice: VehicleVoice TargetableUnit: TargetTypes: Ground, Water HiddenUnderFog: @@ -384,6 +390,8 @@ UpgradeTypes: selfheal UpgradeMinEnabledLevel: 1 UpgradeManager: + Voiced: + VoiceSet: VehicleVoice ^Building: AppearsOnRadar: diff --git a/mods/cnc/rules/infantry.yaml b/mods/cnc/rules/infantry.yaml index 5d7920fc7f..15558fed49 100644 --- a/mods/cnc/rules/infantry.yaml +++ b/mods/cnc/rules/infantry.yaml @@ -185,7 +185,6 @@ RMBO: Queue: Infantry.GDI Selectable: Bounds: 12,17,0,-6 - Voice: CommandoVoice Mobile: Speed: 71 Health: @@ -206,6 +205,8 @@ RMBO: StandSequences: stand, stand2 AnnounceOnBuild: AnnounceOnKill: + Voiced: + VoiceSet: CommandoVoice PVICE: Inherits: VICE diff --git a/mods/d2k/rules/defaults.yaml b/mods/d2k/rules/defaults.yaml index 13394e55f1..d4cdf27675 100644 --- a/mods/d2k/rules/defaults.yaml +++ b/mods/d2k/rules/defaults.yaml @@ -13,7 +13,6 @@ ROT: 5 SelectionDecorations: Selectable: - Voice: VehicleVoice TargetableUnit: TargetTypes: Ground, C4 Passenger: @@ -52,6 +51,8 @@ MustBeDestroyed: AnnounceOnSeen: Notification: EnemyUnitsDetected + Voiced: + VoiceSet: VehicleVoice ^Tank: AppearsOnRadar: @@ -68,7 +69,6 @@ ROT: 5 SelectionDecorations: Selectable: - Voice: VehicleVoice TargetableUnit: TargetTypes: Ground, C4 Passenger: @@ -107,6 +107,8 @@ MustBeDestroyed: AnnounceOnSeen: Notification: EnemyUnitsDetected + Voiced: + VoiceSet: VehicleVoice ^Husk: Health: @@ -190,7 +192,6 @@ Rough: 70 SelectionDecorations: Selectable: - Voice: InfantryVoice TargetableUnit: TargetTypes: Ground RenderSprites: @@ -241,13 +242,14 @@ TerrainModifiesDamage: TerrainModifier: Rough: 80 + Voiced: + VoiceSet: InfantryVoice ^Plane: AppearsOnRadar: UseLocation: yes SelectionDecorations: Selectable: - Voice: GenericVoice TargetableAircraft: TargetTypes: Air GroundedTargetTypes: Ground @@ -277,6 +279,8 @@ AnnounceOnSeen: Notification: EnemyUnitsDetected RenderUnit: + Voiced: + VoiceSet: GenericVoice ^Helicopter: Inherits: ^Plane diff --git a/mods/d2k/rules/infantry.yaml b/mods/d2k/rules/infantry.yaml index 5999966ab8..88bf58ba66 100644 --- a/mods/d2k/rules/infantry.yaml +++ b/mods/d2k/rules/infantry.yaml @@ -37,7 +37,6 @@ engineer: Description: Infiltrates and captures enemy structures\n Strong vs Buildings\n Weak vs Everything Selectable: Bounds: 12,17,0,0 - Voice: EngineerVoice Health: HP: 25 Mobile: @@ -52,6 +51,8 @@ engineer: -AutoTarget: AttractsWorms: Intensity: 180 + Voiced: + VoiceSet: EngineerVoice bazooka: Inherits: ^Infantry @@ -94,7 +95,6 @@ medic: Description: Heals nearby infantry\n Strong vs Nothing\n Weak vs Everything Selectable: Bounds: 12,17,0,0 - Voice: EngineerVoice Health: HP: 60 Mobile: @@ -112,6 +112,8 @@ medic: -AutoTarget: AttractsWorms: Intensity: 180 + Voiced: + VoiceSet: EngineerVoice fremen: Inherits: ^Infantry @@ -126,7 +128,6 @@ fremen: Prerequisites: ~barracks.atreides, palace, ~techlevel.high Selectable: Bounds: 12,17,0,0 - Voice: FremenVoice Mobile: Speed: 53 Health: @@ -151,6 +152,8 @@ fremen: CloakSound: STEALTH1.WAV UncloakSound: STEALTH2.WAV -MustBeDestroyed: + Voiced: + VoiceSet: FremenVoice grenadier: Inherits: ^Infantry @@ -199,7 +202,6 @@ sardaukar: Description: Elite asssault infantry\n Strong vs Infantry, Vehicles\n Weak vs Artillery Selectable: Bounds: 12,17,0,0 - Voice: GenericVoice Health: HP: 100 Mobile: @@ -217,6 +219,8 @@ sardaukar: AttackFrontal: AttractsWorms: Intensity: 180 + Voiced: + VoiceSet: GenericVoice saboteur: Inherits: ^Infantry @@ -230,7 +234,6 @@ saboteur: Name: Saboteur Description: Sneaky infantry, armed with explosives\n Strong vs Buildings\n Weak vs Everything\n Special Ability: destroy buildings Selectable: - Voice: SaboteurVoice Bounds: 12,17,0,0 Health: HP: 100 @@ -243,4 +246,6 @@ saboteur: -AutoTarget: AttractsWorms: Intensity: 120 + Voiced: + VoiceSet: SaboteurVoice diff --git a/mods/ra/audio/voices.yaml b/mods/ra/audio/voices.yaml index cd628a67d7..1d828bea0f 100644 --- a/mods/ra/audio/voices.yaml +++ b/mods/ra/audio/voices.yaml @@ -27,6 +27,7 @@ VehicleVoice: Voices: Select: vehic1,yessir1,report1,await1 Move: ackno,affirm1 + Unload: ackno,affirm1 EngineerVoice: Voices: diff --git a/mods/ra/rules/civilian.yaml b/mods/ra/rules/civilian.yaml index ff1d5b5f6d..ac6688191c 100644 --- a/mods/ra/rules/civilian.yaml +++ b/mods/ra/rules/civilian.yaml @@ -4,7 +4,8 @@ C1: C2: Inherits: ^CivInfantry Selectable: - Voice: CivilianFemaleVoice + Voiced: + VoiceSet: CivilianFemaleVoice C3: Inherits: ^CivInfantry @@ -12,10 +13,11 @@ C3: C4: Inherits: ^CivInfantry Selectable: - Voice: CivilianFemaleVoice WithInfantryBody: RenderSprites: Image: C2 + Voiced: + VoiceSet: CivilianFemaleVoice C5: Inherits: ^CivInfantry @@ -26,10 +28,11 @@ C5: C6: Inherits: ^CivInfantry Selectable: - Voice: CivilianFemaleVoice WithInfantryBody: RenderSprites: Image: C2 + Voiced: + VoiceSet: CivilianFemaleVoice C7: Inherits: ^CivInfantry @@ -40,10 +43,11 @@ C7: C8: Inherits: ^CivInfantry Selectable: - Voice: CivilianFemaleVoice WithInfantryBody: RenderSprites: Image: C2 + Voiced: + VoiceSet: CivilianFemaleVoice C9: Inherits: ^CivInfantry @@ -54,10 +58,11 @@ C9: C10: Inherits: ^CivInfantry Selectable: - Voice: CivilianFemaleVoice WithInfantryBody: RenderSprites: Image: C2 + Voiced: + VoiceSet: CivilianFemaleVoice FCOM: Inherits: ^TechBuilding diff --git a/mods/ra/rules/defaults.yaml b/mods/ra/rules/defaults.yaml index a066b3293c..5495b10e6d 100644 --- a/mods/ra/rules/defaults.yaml +++ b/mods/ra/rules/defaults.yaml @@ -48,7 +48,6 @@ ROT: 5 SelectionDecorations: Selectable: - Voice: VehicleVoice TargetableUnit: TargetTypes: Ground, Repair, Vehicle Repairable: @@ -83,6 +82,8 @@ MustBeDestroyed: AnnounceOnSeen: Notification: EnemyDetected + Voiced: + VoiceSet: VehicleVoice ^Tank: Inherits@1: ^ExistsInWorld @@ -101,7 +102,6 @@ ROT: 5 SelectionDecorations: Selectable: - Voice: VehicleVoice TargetableUnit: TargetTypes: Ground, C4, Repair, Tank Repairable: @@ -145,6 +145,8 @@ WaterCorpsePalette: AnnounceOnSeen: Notification: EnemyDetected + Voiced: + VoiceSet: VehicleVoice ^Infantry: Inherits@1: ^ExistsInWorld @@ -168,7 +170,6 @@ Beach: 80 SelectionDecorations: Selectable: - Voice: GenericVoice TargetableUnit: TargetTypes: Ground, Infantry, Disguise RenderSprites: @@ -221,6 +222,8 @@ MustBeDestroyed: AnnounceOnSeen: Notification: EnemyDetected + Voiced: + VoiceSet: GenericVoice ^Ship: Inherits@1: ^ExistsInWorld @@ -232,7 +235,6 @@ Water: 100 SelectionDecorations: Selectable: - Voice: VehicleVoice TargetableUnit: TargetTypes: Ground, Water, Repair HiddenUnderFog: @@ -254,6 +256,8 @@ Notification: EnemyDetected EditorTilesetFilter: ExcludeTilesets: INTERIOR + Voiced: + VoiceSet: VehicleVoice ^Plane: Inherits@1: ^ExistsInWorld @@ -263,7 +267,6 @@ UseLocation: true SelectionDecorations: Selectable: - Voice: GenericVoice TargetableAircraft: TargetTypes: Air GroundedTargetTypes: Ground, Repair @@ -290,6 +293,8 @@ MustBeDestroyed: AnnounceOnSeen: Notification: EnemyDetected + Voiced: + VoiceSet: GenericVoice ^Helicopter: Inherits: ^Plane @@ -446,7 +451,6 @@ ^CivInfantry: Inherits: ^Infantry Selectable: - Voice: CivilianMaleVoice Bounds: 12,17,0,-9 Valued: Cost: 70 @@ -466,6 +470,8 @@ Types: CivilianInfantry WithInfantryBody: ScaredyCat: + Voiced: + VoiceSet: CivilianMaleVoice ^CivBuilding: Inherits: ^TechBuilding diff --git a/mods/ra/rules/infantry.yaml b/mods/ra/rules/infantry.yaml index 22f82ec472..d5315b335b 100644 --- a/mods/ra/rules/infantry.yaml +++ b/mods/ra/rules/infantry.yaml @@ -11,7 +11,6 @@ DOG: Name: Attack Dog Description: Anti-infantry unit.\nCan detect cloaked units and spies.\n Strong vs Infantry\n Weak vs Vehicles Selectable: - Voice: DogVoice Bounds: 12,17,-1,-4 Health: HP: 12 @@ -29,6 +28,8 @@ DOG: IgnoresDisguise: DetectCloaked: Range: 5 + Voiced: + VoiceSet: DogVoice E1: Inherits: ^Infantry @@ -184,7 +185,6 @@ E6: Name: Engineer Description: Infiltrates and captures enemy structures.\n Strong vs Nothing\n Weak vs Everything Selectable: - Voice: EngineerVoice Bounds: 12,17,0,-9 Health: HP: 25 @@ -204,6 +204,8 @@ E6: WithInfantryBody: IdleSequences: idle1,idle2 StandSequences: stand,stand2 + Voiced: + VoiceSet: EngineerVoice SPY: Inherits: ^Infantry @@ -220,7 +222,6 @@ SPY: GenericName: Soldier Description: Infiltrates enemy structures for intel or\nsabotage. Exact effect depends on the\nbuilding infiltrated.\n Strong vs Nothing\n Weak vs Everything\n Special Ability: Disguised Selectable: - Voice: SpyVoice Bounds: 12,17,0,-9 Health: HP: 25 @@ -245,6 +246,8 @@ SPY: Armament: Weapon: SilencedPPK AttackFrontal: + Voiced: + VoiceSet: SpyVoice SPY.England: Inherits: SPY @@ -272,7 +275,6 @@ E7: Name: Tanya Description: Elite commando infantry. Armed with\ndual pistols and C4.\n Strong vs Infantry, Buildings\n Weak vs Vehicles\n Special Ability: Destroy Building with C4\n\nMaximum 1 can be trained Selectable: - Voice: TanyaVoice Bounds: 12,17,0,-9 Health: HP: 100 @@ -302,6 +304,8 @@ E7: IdleSequences: idle1,idle2 AnnounceOnBuild: AnnounceOnKill: + Voiced: + VoiceSet: TanyaVoice MEDI: Inherits: ^Infantry @@ -316,7 +320,6 @@ MEDI: Name: Medic Description: Heals nearby infantry.\n Strong vs Nothing\n Weak vs Everything Selectable: - Voice: MedicVoice Bounds: 12,17,0,-9 Health: HP: 80 @@ -340,6 +343,8 @@ MEDI: WithInfantryBody: IdleSequences: idle1,idle2 AttackSequence: heal + Voiced: + VoiceSet: MedicVoice MECH: Inherits: ^Infantry @@ -354,7 +359,6 @@ MECH: Name: Mechanic Description: Repairs nearby vehicles and restores\nhusks to working condition.\n Strong vs Nothing\n Weak vs Everything Selectable: - Voice: MechanicVoice Bounds: 12,17,0,-9 Health: HP: 80 @@ -380,11 +384,12 @@ MECH: WithInfantryBody: IdleSequences: idle1,idle2 AttackSequence: heal + Voiced: + VoiceSet: MechanicVoice EINSTEIN: Inherits: ^Infantry Selectable: - Voice: EinsteinVoice Bounds: 12,17,0,-9 Valued: Cost: 10 @@ -401,11 +406,12 @@ EINSTEIN: Types: CivilianInfantry WithInfantryBody: ScaredyCat: + Voiced: + VoiceSet: EinsteinVoice DELPHI: Inherits: ^Infantry Selectable: - Voice: CivilianMaleVoice Bounds: 12,17,0,-9 Valued: Cost: 10 @@ -422,6 +428,8 @@ DELPHI: Types: CivilianInfantry WithInfantryBody: ScaredyCat: + Voiced: + VoiceSet: CivilianMaleVoice CHAN: Inherits: ^CivInfantry @@ -433,7 +441,8 @@ GNRL: Tooltip: Name: General Selectable: - Voice: StavrosVoice + Voiced: + VoiceSet: StavrosVoice THF: Inherits: ^Infantry @@ -443,7 +452,6 @@ THF: Name: Thief Description: Steals enemy credits.\n Strong vs Nothing\n Weak vs Everything\n Selectable: - Voice: ThiefVoice Bounds: 12,17,0,-9 Health: HP: 25 @@ -460,6 +468,8 @@ THF: Prone50Percent: 50 DamageTriggers: TriggerProne -AutoTarget: + Voiced: + VoiceSet: ThiefVoice HIJACKER: Inherits: ^Infantry @@ -474,7 +484,6 @@ HIJACKER: Name: Hijacker Description: Hijacks enemy vehicles. Unarmed\n Strong vs Tanks\n Weak vs Infantry, Aircraft Selectable: - Voice: ThiefVoice Bounds: 12,17,0,-9 Health: HP: 50 @@ -487,6 +496,8 @@ HIJACKER: Captures: CaptureTypes: vehicle -AutoTarget: + Voiced: + VoiceSet: ThiefVoice SHOK: Inherits: ^Infantry @@ -501,7 +512,6 @@ SHOK: Name: Shock Trooper Description: Elite infantry with portable tesla coils.\n Strong vs Infantry\n Weak vs Aircraft Selectable: - Voice: ShokVoice Bounds: 12,17,0,-9 Health: HP: 100 @@ -523,6 +533,8 @@ SHOK: WithInfantryBody: IdleSequences: idle1,idle2 StandSequences: stand,stand2 + Voiced: + VoiceSet: ShokVoice SNIPER: Inherits: ^Infantry @@ -584,7 +596,6 @@ Zombie: BuildPaletteOrder: 200 Prerequisites: ~bio Selectable: - Voice: AntVoice Bounds: 12,17,0,-9 Health: HP: 250 @@ -595,6 +606,8 @@ Zombie: AttackFrontal: Armament: Weapon: claw + Voiced: + VoiceSet: AntVoice Ant: Inherits: ^Infantry @@ -608,7 +621,6 @@ Ant: BuildPaletteOrder: 1954 Prerequisites: ~bio Selectable: - Voice: AntVoice Bounds: 30,30,0,-2 Health: HP: 750 @@ -626,4 +638,6 @@ Ant: TargetTypes: Ground, Infantry WithDeathAnimation: UseDeathTypeSuffix: false + Voiced: + VoiceSet: AntVoice diff --git a/mods/ts/audio/voices.yaml b/mods/ts/audio/voices.yaml index 0f83f7b9c8..a1cc798eba 100644 --- a/mods/ts/audio/voices.yaml +++ b/mods/ts/audio/voices.yaml @@ -161,6 +161,7 @@ Vehicle: Select: 25-I000, 25-I002, 25-I004, 25-I006 Move: 25-I012, 25-I014, 25-I016, 25-I018, 25-I022 Attack: 25-I014, 25-I022, 25-I024, 25-I026 + Unload: 25-I018 Mech: Voices: diff --git a/mods/ts/rules/aircraft.yaml b/mods/ts/rules/aircraft.yaml index ca8e02ce40..bf1f5dd041 100644 --- a/mods/ts/rules/aircraft.yaml +++ b/mods/ts/rules/aircraft.yaml @@ -207,7 +207,8 @@ SCRIN: Prerequisites: ~nahpad, natech Selectable: Bounds: 30,24 - Voice: Scrin + Voiced: + VoiceSet: Scrin Plane: MaximumPitch: 90 ROT: 3 diff --git a/mods/ts/rules/civilian-infantry.yaml b/mods/ts/rules/civilian-infantry.yaml index 998e22f6f8..85e1de3850 100644 --- a/mods/ts/rules/civilian-infantry.yaml +++ b/mods/ts/rules/civilian-infantry.yaml @@ -6,7 +6,8 @@ WEEDGUY: Name: Chem Spray Infantry Selectable: Bounds: 12,17,0,-6 - Voice: Weed + Voiced: + VoiceSet: Weed Mobile: Speed: 42 Health: @@ -35,7 +36,8 @@ UMAGON: Name: Umagon Selectable: Bounds: 12,17,0,-6 - Voice: Umagon + Voiced: + VoiceSet: Umagon Mobile: Speed: 71 Health: @@ -65,8 +67,9 @@ CHAMSPY: Cost: 700 DisguiseToolTip: Name: Chameleon Spy + Voiced: + VoiceSet: Spy Selectable: - Voice: Spy Bounds: 12,17,0,-9 Health: HP: 120 @@ -99,7 +102,8 @@ MUTANT: Name: Mutant Selectable: Bounds: 12,17,0,-9 - Voice: Mutant + Voiced: + VoiceSet: Mutant Health: HP: 50 PoisonedByTiberium: @@ -130,7 +134,8 @@ MWMN: Name: Mutant Soldier Selectable: Bounds: 12,17,0,-9 - Voice: CivilianFemale + Voiced: + VoiceSet: CivilianFemale Health: HP: 50 PoisonedByTiberium: @@ -161,7 +166,8 @@ MUTANT3: Name: Mutant Sergeant Selectable: Bounds: 12,17,0,-9 - Voice: Mutant + Voiced: + VoiceSet: Mutant Health: HP: 50 PoisonedByTiberium: @@ -192,7 +198,8 @@ TRATOS: Name: Tratos Selectable: Bounds: 12,17,0,-9 - Voice: Tratos + Voiced: + VoiceSet: Tratos Health: HP: 200 PoisonedByTiberium: @@ -221,7 +228,8 @@ OXANNA: Name: Oxanna Selectable: Bounds: 12,17,0,-9 - Voice: Oxanna + Voiced: + VoiceSet: Oxanna Health: HP: 50 Mobile: @@ -248,7 +256,8 @@ SLAV: Name: Slavick Selectable: Bounds: 12,17,0,-9 - Voice: Slavick + Voiced: + VoiceSet: Slavick Health: HP: 300 Mobile: @@ -284,8 +293,8 @@ DOGGIE: Range: 4c0 Mobile: Speed: 113 - Selectable: - Voice: Fiend + Voiced: + VoiceSet: Fiend TargetableUnit: TargetTypes: Ground Armament: @@ -314,8 +323,8 @@ VISSML: Speed: 113 ROT: 16 -Crushable: - Selectable: - Voice: Fiend + Voiced: + VoiceSet: Fiend TargetableUnit: TargetTypes: Ground -AutoTarget: @@ -342,8 +351,8 @@ VISLRG: Speed: 113 ROT: 16 -Crushable: - Selectable: - Voice: Fiend + Voiced: + VoiceSet: Fiend TargetableUnit: TargetTypes: Ground Armament: diff --git a/mods/ts/rules/defaults.yaml b/mods/ts/rules/defaults.yaml index 86d92e21a0..a1b9f3eb33 100644 --- a/mods/ts/rules/defaults.yaml +++ b/mods/ts/rules/defaults.yaml @@ -185,7 +185,8 @@ SelectionDecorations: Palette: pips Selectable: - Voice: Infantry + Voiced: + VoiceSet: Infantry TargetableUnit: TargetTypes: Ground, Infantry RenderSprites: @@ -250,8 +251,9 @@ ^CivilianInfantry: Inherits: ^Infantry Selectable: - Voice: Civilian Bounds: 12,17,0,-9 + Voiced: + VoiceSet: Civilian Valued: Cost: 10 Tooltip: @@ -281,10 +283,11 @@ Tiberium: 80 BlueTiberium: 80 ROT: 5 + Selectable: SelectionDecorations: Palette: pips - Selectable: - Voice: Vehicle + Voiced: + VoiceSet: Vehicle TargetableUnit: TargetTypes: Ground, Vehicle Repairable: @@ -365,10 +368,11 @@ Tiberium: 80 BlueTiberium: 80 ROT: 5 + Selectable: SelectionDecorations: Palette: pips - Selectable: - Voice: Vehicle + Voiced: + VoiceSet: Vehicle TargetableUnit: TargetTypes: Ground, Vehicle Repairable: @@ -442,10 +446,11 @@ TargetableAircraft: TargetTypes: Air GroundedTargetTypes: Ground + Selectable: SelectionDecorations: Palette: pips - Selectable: - Voice: Heli + Voiced: + VoiceSet: Heli Helicopter: RepairBuildings: gadept RearmBuildings: diff --git a/mods/ts/rules/gdi-infantry.yaml b/mods/ts/rules/gdi-infantry.yaml index 50808a8910..df4542e4f4 100644 --- a/mods/ts/rules/gdi-infantry.yaml +++ b/mods/ts/rules/gdi-infantry.yaml @@ -44,7 +44,8 @@ MEDIC: Prerequisites: ~gapile Selectable: Bounds: 12,17,0,-6 - Voice: Medic + Voiced: + VoiceSet: Medic Mobile: Speed: 56 Health: diff --git a/mods/ts/rules/gdi-vehicles.yaml b/mods/ts/rules/gdi-vehicles.yaml index bad3e0193a..b6b18e0ad8 100644 --- a/mods/ts/rules/gdi-vehicles.yaml +++ b/mods/ts/rules/gdi-vehicles.yaml @@ -106,8 +106,9 @@ SMECH: Weapon: AssaultCannon RenderSprites: WithInfantryBody: + Voiced: + VoiceSet: Mech Selectable: - Voices: Mech Bounds: 20, 32, 0, -8 MMCH: diff --git a/mods/ts/rules/nod-infantry.yaml b/mods/ts/rules/nod-infantry.yaml index 5312403718..a14c303faf 100644 --- a/mods/ts/rules/nod-infantry.yaml +++ b/mods/ts/rules/nod-infantry.yaml @@ -11,7 +11,8 @@ E3: Description: Anti-tank infantry.\n Strong vs Vehicles, Aircraft, Buildings\n Weak vs Infantry Selectable: Bounds: 12,17,0,-9 - Voice: Rocket + Voiced: + VoiceSet: Rocket Health: HP: 100 Mobile: @@ -47,7 +48,8 @@ CYBORG: -Crushable: Selectable: Bounds: 14,30,0,-7 - Voice: Cyborg + Voiced: + VoiceSet: Cyborg Mobile: Speed: 56 Health: @@ -88,7 +90,8 @@ CYC2: -Crushable: Selectable: Bounds: 14,30,0,-7 - Voice: CyborgCommando + Voiced: + VoiceSet: CyborgCommando Mobile: Speed: 56 Health: @@ -126,7 +129,8 @@ MHIJACK: Description: Hijacks enemy vehicles.\n Unarmed Selectable: Bounds: 12,17,0,-9 - Voice: Hijacker + Voiced: + VoiceSet: Hijacker Health: HP: 300 PoisonedByTiberium: diff --git a/mods/ts/rules/nod-support.yaml b/mods/ts/rules/nod-support.yaml index 76198480ec..93445c9d71 100644 --- a/mods/ts/rules/nod-support.yaml +++ b/mods/ts/rules/nod-support.yaml @@ -165,6 +165,8 @@ GATICK: Type: Concrete RevealsShroud: Range: 5c0 + Voiced: + VoiceSet: Vehicle Turreted: ROT: 6 InitialFacing: 128 @@ -215,8 +217,8 @@ GAARTY: Type: Light RevealsShroud: Range: 9c0 - Selectable: - Voice: Vehicle + Voiced: + VoiceSet: Vehicle Turreted: ROT: 5 InitialFacing: 128 diff --git a/mods/ts/rules/shared-infantry.yaml b/mods/ts/rules/shared-infantry.yaml index 47c235b37a..0ea97851f4 100644 --- a/mods/ts/rules/shared-infantry.yaml +++ b/mods/ts/rules/shared-infantry.yaml @@ -49,7 +49,8 @@ ENGINEER: Prerequisites: ~barracks Selectable: Bounds: 12,17,0,-6 - Voice: Engineer + Voiced: + VoiceSet: Engineer Mobile: Speed: 56 Health: