diff --git a/OpenRA.Game/GameRules/SoundInfo.cs b/OpenRA.Game/GameRules/SoundInfo.cs index 555af9052d..c674b28b79 100644 --- a/OpenRA.Game/GameRules/SoundInfo.cs +++ b/OpenRA.Game/GameRules/SoundInfo.cs @@ -33,19 +33,41 @@ namespace OpenRA.GameRules { FieldLoader.Load(this, y); - VoicePools = Exts.Lazy(() => Voices.ToDictionary(a => a.Key, a => new SoundPool(a.Value))); - NotificationsPools = Exts.Lazy(() => Notifications.ToDictionary(a => a.Key, a => new SoundPool(a.Value))); + VoicePools = Exts.Lazy(() => Voices.ToDictionary(a => a.Key, a => new SoundPool(0, a.Value))); + NotificationsPools = Exts.Lazy(() => ParseSoundPool(y, "Notifications")); + } + + Dictionary ParseSoundPool(MiniYaml y, string key) + { + var ret = new Dictionary(); + var classifiction = y.Nodes.First(x => x.Key == key); + foreach (var t in classifiction.Value.Nodes) + { + var rateLimit = 0; + var rateLimitNode = t.Value.Nodes.FirstOrDefault(x => x.Key == "RateLimit"); + if (rateLimitNode != null) + rateLimit = FieldLoader.GetValue(rateLimitNode.Key, rateLimitNode.Value.Value); + + var names = FieldLoader.GetValue(t.Key, t.Value.Value); + var sp = new SoundPool(rateLimit, names); + ret.Add(t.Key, sp); + } + + return ret; } } public class SoundPool { readonly string[] clips; + readonly int rateLimit; readonly List liveclips = new List(); + long lastPlayed = 0; - public SoundPool(params string[] clips) + public SoundPool(int rateLimit, params string[] clips) { this.clips = clips; + this.rateLimit = rateLimit; } public string GetNext() @@ -53,8 +75,19 @@ namespace OpenRA.GameRules if (liveclips.Count == 0) liveclips.AddRange(clips); + // Avoid crashing if there's no clips at all if (liveclips.Count == 0) - return null; /* avoid crashing if there's no clips at all */ + return null; + + // Perform rate limiting if necessary + if (rateLimit != 0) + { + var now = Game.RunTime; + if (lastPlayed != 0 && now < lastPlayed + rateLimit) + return null; + + lastPlayed = now; + } var i = Game.CosmeticRandom.Next(liveclips.Count); var s = liveclips[i]; diff --git a/mods/cnc/audio/notifications.yaml b/mods/cnc/audio/notifications.yaml index 7a4cd1fcda..73f69aa0fa 100644 --- a/mods/cnc/audio/notifications.yaml +++ b/mods/cnc/audio/notifications.yaml @@ -6,11 +6,13 @@ Speech: AirstrikeReady: airredy1 BaseAttack: baseatk1 Building: bldging1 + RateLimit: 600 BuildingCannotPlaceAudio: deploy1 BuildingCaptured: capt1 BuildingInProgress: bldg1 BuildingLost: strclost Cancelled: cancel1 + RateLimit: 500 CivilianBuildingCaptured: civcapt1 CivilianKilled: civdead1 ConstructionComplete: constru1 @@ -41,9 +43,11 @@ Speech: SilosNeeded: silos1 StartGame: Training: bldging1 + RateLimit: 800 UnitDestroyed: dead1 UnitLost: unitlost UnitReady: unitredy + RateLimit: 900 Win: accom1 DisablePrefixes: AbilityInsufficientPower, BaseAttack, Building, BuildingCannotPlaceAudio, BuildingInProgress, BuildingLost, Cancelled, CivilianBuildingCaptured, CivilianKilled, ConstructionComplete, EnemyUnitsApproaching, EnemyStructureDestroyed, EnemyPlanesApproaching, HarvesterAttack, InsufficientPower, IonCannonCharging, IonCannonReady, Leave, Lose, LowPower, MissionAccomplished, MissionFailed, NewOptions, NoBuild, NodStructureDestroyed, NotReady, NuclearWarheadApproaching, NuclearWeaponAvailable, NuclearWeaponLaunched, OnHold, PrimaryBuildingSelected, Reinforce, Repairing, SelectTarget, SilosNeeded, Training, UnitLost, UnitReady, Win diff --git a/mods/d2k/audio/notifications.yaml b/mods/d2k/audio/notifications.yaml index d742b91c2b..ea3042b9ec 100644 --- a/mods/d2k/audio/notifications.yaml +++ b/mods/d2k/audio/notifications.yaml @@ -13,11 +13,13 @@ Speech: Notifications: BaseAttack: ATACK Building: BUILD + RateLimit: 600 BuildingCannotPlaceAudio: PLACE BuildingCaptured: CAPT BuildingLost: BLOST BuildingReady: BDRDY Cancelled: CANCL + RateLimit: 500 CannotDeploy: DPLOY DeathHandMissilePrepping: PREP DeathHandMissileReady: DHRDY @@ -50,8 +52,10 @@ Speech: TMinusThree: 3MIN TMinusTwo: 2MIN Training: TRAIN + RateLimit: 800 UnitLost: ULOST UnitReady: UNRDY + RateLimit: 900 UnitRepaired: GANEW UpgradeOptions: UPGOP Upgrading: UPGRD diff --git a/mods/ra/audio/notifications.yaml b/mods/ra/audio/notifications.yaml index f85f236553..9971b4ce1c 100644 --- a/mods/ra/audio/notifications.yaml +++ b/mods/ra/audio/notifications.yaml @@ -17,12 +17,14 @@ Speech: AtomBombPrepping: atprep1 BaseAttack: baseatk1 Building: abldgin1 + RateLimit: 600 BuildingCannotPlaceAudio: nodeply1 BuildingCaptured: strucap1 BuildingInfiltrated: bldginf1 BuildingInProgress: progres1 BuildingProgress: bldgprg1 Cancelled: cancld1 + RateLimit: 500 ChronosphereCharging: chrochr1 ChronosphereReady: chrordy1 ChronosphereTestSuccessful: chroyes1 @@ -97,12 +99,14 @@ Speech: TimerStarted: timergo1 TimerStopped: timerno1 Training: train1 + RateLimit: 800 TwentyMinutesRemaining: 20minr UnitArmorUpgraded: armorup1 UnitFirepowerUpgraded: firepo1 UnitFull: unitful1 UnitLost: unitlst1 UnitReady: unitrdy1 + RateLimit: 900 UnitRepaired: unitrep1 UnitSold: unitsld1 UnitSpeedUpgraded: unitspd1 diff --git a/mods/ts/audio/speech-generic.yaml b/mods/ts/audio/speech-generic.yaml index b616dd172d..079695313a 100644 --- a/mods/ts/audio/speech-generic.yaml +++ b/mods/ts/audio/speech-generic.yaml @@ -14,10 +14,12 @@ Speech: BridgeRepaired2: 00-n128 BridgeRepaired: 00-i118 Building: 00-i216 + RateLimit: 600 BuildingCannotPlaceAudio: 00-i016 #CannotDeployHere BuildingCaptured: 00-i056 BuildingInfiltrated: 00-i014 Cancelled: 00-i220 + RateLimit: 500 ChemicalMissileReady: 00-i152 CivilianKilled: 00-n018 CloakedUnitDetected: 00-i172 @@ -71,10 +73,12 @@ Speech: TiberiumMissileReady2: 01-n194 TiberiumMissileReady: 01-n176 Training: 00-i062 + RateLimit: 800 UnitArmourUpgraded: 00-i068 UnitFirepowerUpgraded: 00-i070 UnitLost: 00-i074 UnitReady: 00-i076 + RateLimit: 900 UnitRepaired: 00-i078 UnitSold: 00-i226 UnitSpeedUpgraded: 00-i080