diff --git a/OpenRA.Mods.Common/Traits/Player/BaseAttackNotifier.cs b/OpenRA.Mods.Common/Traits/Player/BaseAttackNotifier.cs index 59a4ee0e35..e8e03aeb7a 100644 --- a/OpenRA.Mods.Common/Traits/Player/BaseAttackNotifier.cs +++ b/OpenRA.Mods.Common/Traits/Player/BaseAttackNotifier.cs @@ -19,8 +19,8 @@ namespace OpenRA.Mods.Common.Traits "Attach this to the player actor.")] public class BaseAttackNotifierInfo : TraitInfo { - [Desc("Minimum duration (in seconds) between notification events.")] - public readonly int NotifyInterval = 30; + [Desc("Minimum duration (in milliseconds) between notification events.")] + public readonly int NotifyInterval = 30000; public readonly Color RadarPingColor = Color.Red; @@ -44,13 +44,13 @@ namespace OpenRA.Mods.Common.Traits readonly RadarPings radarPings; readonly BaseAttackNotifierInfo info; - int lastAttackTime; + long lastAttackTime; public BaseAttackNotifier(Actor self, BaseAttackNotifierInfo info) { radarPings = self.World.WorldActor.TraitOrDefault(); this.info = info; - lastAttackTime = -info.NotifyInterval * 25; + lastAttackTime = -info.NotifyInterval; } void INotifyDamage.Damaged(Actor self, AttackInfo e) @@ -71,7 +71,7 @@ namespace OpenRA.Mods.Common.Traits if (e.Attacker.Owner.IsAlliedWith(self.Owner) && e.Damage.Value <= 0) return; - if (self.World.WorldTick - lastAttackTime > info.NotifyInterval * 25) + if (Game.RunTime > lastAttackTime + info.NotifyInterval) { var rules = self.World.Map.Rules; Game.Sound.PlayNotification(rules, self.Owner, "Speech", info.Notification, self.Owner.Faction.InternalName); @@ -82,9 +82,9 @@ namespace OpenRA.Mods.Common.Traits Game.Sound.PlayNotification(rules, p, "Speech", info.AllyNotification, p.Faction.InternalName); radarPings?.Add(() => self.Owner.IsAlliedWith(self.World.RenderPlayer), self.CenterPosition, info.RadarPingColor, info.RadarPingDuration); - } - lastAttackTime = self.World.WorldTick; + lastAttackTime = Game.RunTime; + } } } } diff --git a/OpenRA.Mods.Common/Traits/Player/HarvesterAttackNotifier.cs b/OpenRA.Mods.Common/Traits/Player/HarvesterAttackNotifier.cs index 19bcd3514a..6ea5959700 100644 --- a/OpenRA.Mods.Common/Traits/Player/HarvesterAttackNotifier.cs +++ b/OpenRA.Mods.Common/Traits/Player/HarvesterAttackNotifier.cs @@ -19,8 +19,8 @@ namespace OpenRA.Mods.Common.Traits [TraitLocation(SystemActors.Player)] public class HarvesterAttackNotifierInfo : TraitInfo { - [Desc("Minimum duration (in seconds) between notification events.")] - public readonly int NotifyInterval = 30; + [Desc("Minimum duration (in milliseconds) between notification events.")] + public readonly int NotifyInterval = 30000; public readonly Color RadarPingColor = Color.Red; @@ -39,13 +39,13 @@ namespace OpenRA.Mods.Common.Traits readonly RadarPings radarPings; readonly HarvesterAttackNotifierInfo info; - int lastAttackTime; + long lastAttackTime; public HarvesterAttackNotifier(Actor self, HarvesterAttackNotifierInfo info) { radarPings = self.World.WorldActor.TraitOrDefault(); this.info = info; - lastAttackTime = -info.NotifyInterval * 25; + lastAttackTime = -info.NotifyInterval; } void INotifyDamage.Damaged(Actor self, AttackInfo e) @@ -58,14 +58,13 @@ namespace OpenRA.Mods.Common.Traits if (!self.Info.HasTraitInfo()) return; - if (self.World.WorldTick - lastAttackTime > info.NotifyInterval * 25) + if (Game.RunTime > lastAttackTime + info.NotifyInterval) { Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.Notification, self.Owner.Faction.InternalName); - radarPings?.Add(() => self.Owner.IsAlliedWith(self.World.RenderPlayer), self.CenterPosition, info.RadarPingColor, info.RadarPingDuration); - } - lastAttackTime = self.World.WorldTick; + lastAttackTime = Game.RunTime; + } } } } diff --git a/OpenRA.Mods.Common/Traits/Player/PlayerResources.cs b/OpenRA.Mods.Common/Traits/Player/PlayerResources.cs index aee94fec89..9a3590103b 100644 --- a/OpenRA.Mods.Common/Traits/Player/PlayerResources.cs +++ b/OpenRA.Mods.Common/Traits/Player/PlayerResources.cs @@ -45,7 +45,7 @@ namespace OpenRA.Mods.Common.Traits public readonly string InsufficientFundsNotification = null; [Desc("Delay (in ticks) during which warnings will be muted.")] - public readonly int InsufficientFundsNotificationDelay = 750; + public readonly int InsufficientFundsNotificationInterval = 30000; [NotificationReference("Sounds")] public readonly string CashTickUpNotification = null; @@ -83,6 +83,8 @@ namespace OpenRA.Mods.Common.Traits if (!int.TryParse(startingCash, out Cash)) Cash = info.DefaultCash; + + lastNotificationTime = -Info.InsufficientFundsNotificationInterval; } [Sync] @@ -97,7 +99,7 @@ namespace OpenRA.Mods.Common.Traits public int Earned; public int Spent; - int lastNotificationTick; + long lastNotificationTime; public int ChangeCash(int amount) { @@ -178,9 +180,9 @@ namespace OpenRA.Mods.Common.Traits if (Cash + Resources < num) { if (notifyLowFunds && !string.IsNullOrEmpty(Info.InsufficientFundsNotification) && - owner.World.WorldTick - lastNotificationTick >= Info.InsufficientFundsNotificationDelay) + Game.RunTime > lastNotificationTime + Info.InsufficientFundsNotificationInterval) { - lastNotificationTick = owner.World.WorldTick; + lastNotificationTime = Game.RunTime; Game.Sound.PlayNotification(owner.World.Map.Rules, owner, "Speech", Info.InsufficientFundsNotification, owner.Faction.InternalName); } diff --git a/OpenRA.Mods.Common/Traits/Player/ResourceStorageWarning.cs b/OpenRA.Mods.Common/Traits/Player/ResourceStorageWarning.cs index db2d03d3b3..382ed082f2 100644 --- a/OpenRA.Mods.Common/Traits/Player/ResourceStorageWarning.cs +++ b/OpenRA.Mods.Common/Traits/Player/ResourceStorageWarning.cs @@ -17,8 +17,8 @@ namespace OpenRA.Mods.Common.Traits [Desc("Provides the player with an audible warning when their storage is nearing full.")] public class ResourceStorageWarningInfo : TraitInfo, Requires { - [Desc("Interval, in seconds, at which to check if more storage is needed.")] - public readonly int AdviceInterval = 20; + [Desc("Interval (in milliseconds) at which to check if more storage is needed.")] + public readonly int AdviceInterval = 20000; [Desc("The percentage threshold above which a warning is played.")] public readonly int Threshold = 80; @@ -35,7 +35,7 @@ namespace OpenRA.Mods.Common.Traits readonly ResourceStorageWarningInfo info; readonly PlayerResources resources; - int nextSiloAdviceTime = 0; + long lastSiloAdviceTime; public ResourceStorageWarning(Actor self, ResourceStorageWarningInfo info) { @@ -45,14 +45,14 @@ namespace OpenRA.Mods.Common.Traits void ITick.Tick(Actor self) { - if (--nextSiloAdviceTime <= 0) + if (Game.RunTime > lastSiloAdviceTime + info.AdviceInterval) { var owner = self.Owner; if (resources.Resources > info.Threshold * resources.ResourceCapacity / 100) Game.Sound.PlayNotification(self.World.Map.Rules, owner, "Speech", info.Notification, owner.Faction.InternalName); - nextSiloAdviceTime = info.AdviceInterval * 1000 / self.World.Timestep; + lastSiloAdviceTime = Game.RunTime; } } } diff --git a/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs b/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs index fb2bb9e099..bcc071ae7b 100644 --- a/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs +++ b/OpenRA.Mods.Common/Traits/Power/Player/PowerManager.cs @@ -19,7 +19,8 @@ namespace OpenRA.Mods.Common.Traits [Desc("Attach this to the player actor.")] public class PowerManagerInfo : TraitInfo, Requires { - public readonly int AdviceInterval = 250; + [Desc("Interval (in milliseconds) at which to warn the player of low power.")] + public readonly int AdviceInterval = 10000; [NotificationReference("Speech")] public readonly string SpeechNotification = null; @@ -50,7 +51,7 @@ namespace OpenRA.Mods.Common.Traits public int PowerOutageRemainingTicks { get; private set; } public int PowerOutageTotalTicks { get; private set; } - int nextPowerAdviceTime = 0; + long lastPowerAdviceTime; bool isLowPower = false; bool wasLowPower = false; bool wasHackEnabled; @@ -128,8 +129,9 @@ namespace OpenRA.Mods.Common.Traits if (isLowPower != wasLowPower) UpdatePowerRequiringActors(); + // Force the notification to play immediately if (isLowPower && !wasLowPower) - nextPowerAdviceTime = 0; + lastPowerAdviceTime = -info.AdviceInterval; wasLowPower = isLowPower; } @@ -156,10 +158,10 @@ namespace OpenRA.Mods.Common.Traits UpdatePowerState(); } - if (isLowPower && --nextPowerAdviceTime <= 0) + if (isLowPower && Game.RunTime > lastPowerAdviceTime + info.AdviceInterval) { Game.Sound.PlayNotification(self.World.Map.Rules, self.Owner, "Speech", info.SpeechNotification, self.Owner.Faction.InternalName); - nextPowerAdviceTime = info.AdviceInterval; + lastPowerAdviceTime = Game.RunTime; } if (PowerOutageRemainingTicks > 0 && --PowerOutageRemainingTicks == 0) diff --git a/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs b/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs index 747dada558..a444ecaeee 100644 --- a/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs +++ b/OpenRA.Mods.Common/Traits/Sound/AnnounceOnKill.cs @@ -16,8 +16,8 @@ namespace OpenRA.Mods.Common.Traits.Sound [Desc("Play the Kill voice of this actor when eliminating enemies.")] public class AnnounceOnKillInfo : TraitInfo { - [Desc("Minimum duration (in seconds) between sound events.")] - public readonly int Interval = 5; + [Desc("Minimum duration (in milliseconds) between sound events.")] + public readonly int Interval = 5000; [VoiceReference] [Desc("Voice to use when killing something.")] @@ -30,12 +30,12 @@ namespace OpenRA.Mods.Common.Traits.Sound { readonly AnnounceOnKillInfo info; - int lastAnnounce; + long lastAnnounce; public AnnounceOnKill(Actor self, AnnounceOnKillInfo info) { this.info = info; - lastAnnounce = -info.Interval * 25; + lastAnnounce = -info.Interval; } void INotifyAppliedDamage.AppliedDamage(Actor self, Actor damaged, AttackInfo e) @@ -43,10 +43,10 @@ namespace OpenRA.Mods.Common.Traits.Sound // Don't notify suicides if (e.DamageState == DamageState.Dead && damaged != e.Attacker) { - if (self.World.WorldTick - lastAnnounce > info.Interval * 25) + if (Game.RunTime > lastAnnounce + info.Interval) self.PlayVoice(info.Voice); - lastAnnounce = self.World.WorldTick; + lastAnnounce = Game.RunTime; } } } diff --git a/OpenRA.Mods.Common/UpdateRules/Rules/20201213/UseMillisecondsForSounds.cs b/OpenRA.Mods.Common/UpdateRules/Rules/20201213/UseMillisecondsForSounds.cs new file mode 100644 index 0000000000..cfa22bd37d --- /dev/null +++ b/OpenRA.Mods.Common/UpdateRules/Rules/20201213/UseMillisecondsForSounds.cs @@ -0,0 +1,92 @@ +#region Copyright & License Information +/* + * Copyright 2007-2021 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, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using System.Collections.Generic; + +namespace OpenRA.Mods.Common.UpdateRules.Rules +{ + public class UseMillisecondsForSounds : UpdateRule + { + public override string Name => "Convert announcement/notifier intervals to real (milli)seconds."; + + public override string Description => + "AnnounceOnKill.Interval, Harvester- and BaseAttackNotifier.NotifyInterval and\n" + + "ResourceStorageWarning.AdviceInterval were using 'fake' seconds (value * 25 ticks).\n" + + "PowerManager.AdviceInterval and PlayerResources.InsufficientFundsNotificationDelay were using ticks.\n" + + "Converted all of those to use real milliseconds instead."; + + public override IEnumerable UpdateActorNode(ModData modData, MiniYamlNode actorNode) + { + foreach (var announce in actorNode.ChildrenMatching("AnnounceOnKill")) + { + var intervalNode = announce.LastChildMatching("Interval"); + if (intervalNode != null) + { + var interval = intervalNode.NodeValue(); + intervalNode.Value.Value = FieldSaver.FormatValue(interval * 1000); + } + } + + foreach (var notifier in actorNode.ChildrenMatching("BaseAttackNotifier")) + { + var notifyIntervalNode = notifier.LastChildMatching("NotifyInterval"); + if (notifyIntervalNode != null) + { + var notifyInterval = notifyIntervalNode.NodeValue(); + notifyIntervalNode.Value.Value = FieldSaver.FormatValue(notifyInterval * 1000); + } + } + + foreach (var notifier in actorNode.ChildrenMatching("HarvesterAttackNotifier")) + { + var notifyIntervalNode = notifier.LastChildMatching("NotifyInterval"); + if (notifyIntervalNode != null) + { + var notifyInterval = notifyIntervalNode.NodeValue(); + notifyIntervalNode.Value.Value = FieldSaver.FormatValue(notifyInterval * 1000); + } + } + + foreach (var rsw in actorNode.ChildrenMatching("ResourceStorageWarning")) + { + var adviceIntervalNode = rsw.LastChildMatching("AdviceInterval"); + if (adviceIntervalNode != null) + { + var adviceInterval = adviceIntervalNode.NodeValue(); + adviceIntervalNode.Value.Value = FieldSaver.FormatValue(adviceInterval * 1000); + } + } + + foreach (var pm in actorNode.ChildrenMatching("PowerManager")) + { + var adviceIntervalNode = pm.LastChildMatching("AdviceInterval"); + if (adviceIntervalNode != null) + { + var adviceInterval = adviceIntervalNode.NodeValue(); + adviceIntervalNode.Value.Value = FieldSaver.FormatValue(adviceInterval * 40); + } + } + + foreach (var pr in actorNode.ChildrenMatching("PlayerResources")) + { + var noFundsIntervalNode = pr.LastChildMatching("InsufficientFundsNotificationDelay"); + if (noFundsIntervalNode != null) + { + var noFundsInterval = noFundsIntervalNode.NodeValue(); + noFundsIntervalNode.Value.Value = FieldSaver.FormatValue(noFundsInterval * 40); + noFundsIntervalNode.RenameKey("InsufficientFundsNotificationInterval"); + } + } + + yield break; + } + } +} diff --git a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs index 15fc433b52..b8dcda4985 100644 --- a/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs +++ b/OpenRA.Mods.Common/UpdateRules/UpdatePath.cs @@ -95,6 +95,7 @@ namespace OpenRA.Mods.Common.UpdateRules new ConvertBoundsToWDist(), new RemoveSmokeTrailWhenDamaged(), new ReplaceCrateSecondsWithTicks(), + new UseMillisecondsForSounds(), }) }; diff --git a/mods/d2k/rules/player.yaml b/mods/d2k/rules/player.yaml index 77a0dc9a45..724a8246f5 100644 --- a/mods/d2k/rules/player.yaml +++ b/mods/d2k/rules/player.yaml @@ -92,7 +92,7 @@ Player: LeaveNotification: Leave ConquestVictoryConditions: PowerManager: - AdviceInterval: 650 + AdviceInterval: 26000 SpeechNotification: LowPower AllyRepair: PlayerResources: @@ -157,7 +157,7 @@ Player: HarvesterInsurance: GrantConditionOnPrerequisiteManager: ResourceStorageWarning: - AdviceInterval: 26 + AdviceInterval: 26000 PlayerExperience: GameSaveViewportManager: PlayerRadarTerrain: