diff --git a/OpenRA.Game/Sound/Sound.cs b/OpenRA.Game/Sound/Sound.cs index 0240737948..2dfa54b18b 100644 --- a/OpenRA.Game/Sound/Sound.cs +++ b/OpenRA.Game/Sound/Sound.cs @@ -113,6 +113,11 @@ namespace OpenRA InternalSoundVolume * volumeModifier, true); } + public static void StopAudio() + { + soundEngine.StopAllSounds(); + } + public static ISound Play(string name) { return Play(null, name, true, WPos.Zero, 1f); } public static ISound Play(string name, WPos pos) { return Play(null, name, false, pos, 1f); } public static ISound Play(string name, float volumeModifier) { return Play(null, name, true, WPos.Zero, volumeModifier); } diff --git a/OpenRA.Game/Traits/TraitsInterfaces.cs b/OpenRA.Game/Traits/TraitsInterfaces.cs index 541e8cf7fe..d612675bec 100644 --- a/OpenRA.Game/Traits/TraitsInterfaces.cs +++ b/OpenRA.Game/Traits/TraitsInterfaces.cs @@ -339,7 +339,11 @@ namespace OpenRA.Traits public interface ILintPass { void Run(Action emitError, Action emitWarning, Map map); } - public interface IObjectivesPanel { string PanelName { get; } } + public interface IObjectivesPanel + { + string PanelName { get; } + int ExitDelay { get; } + } public interface INotifyObjectivesUpdated { diff --git a/OpenRA.Game/World.cs b/OpenRA.Game/World.cs index 89dd4dd561..16ed7023d8 100644 --- a/OpenRA.Game/World.cs +++ b/OpenRA.Game/World.cs @@ -387,6 +387,7 @@ namespace OpenRA frameEndActions.Clear(); + Sound.StopAudio(); Sound.StopMusic(); Sound.StopVideo(); diff --git a/OpenRA.Mods.Common/Effects/NukeLaunch.cs b/OpenRA.Mods.Common/Effects/NukeLaunch.cs index d1915ad396..3d7ca5abfc 100644 --- a/OpenRA.Mods.Common/Effects/NukeLaunch.cs +++ b/OpenRA.Mods.Common/Effects/NukeLaunch.cs @@ -23,6 +23,7 @@ namespace OpenRA.Mods.Common.Effects readonly Player firedBy; readonly Animation anim; readonly string weapon; + readonly string flashType; readonly WPos ascendSource; readonly WPos ascendTarget; @@ -34,12 +35,13 @@ namespace OpenRA.Mods.Common.Effects WPos pos; int ticks; - public NukeLaunch(Player firedBy, string weapon, WPos launchPos, WPos targetPos, WRange velocity, int delay, bool skipAscent) + public NukeLaunch(Player firedBy, string weapon, WPos launchPos, WPos targetPos, WRange velocity, int delay, bool skipAscent, string flashType) { this.firedBy = firedBy; this.weapon = weapon; this.delay = delay; this.turn = delay / 2; + this.flashType = flashType; var offset = new WVec(WRange.Zero, WRange.Zero, velocity * turn); ascendSource = launchPos; @@ -84,8 +86,9 @@ namespace OpenRA.Mods.Common.Effects weapon.Impact(Target.FromPos(pos), firedBy.PlayerActor, Enumerable.Empty()); world.WorldActor.Trait().AddEffect(20, pos, 5); - foreach (var a in world.ActorsWithTrait()) - a.Trait.Enable(); + foreach (var flash in world.WorldActor.TraitsImplementing()) + if (flash.Info.Type == flashType) + flash.Enable(-1); } public IEnumerable Render(WorldRenderer wr) diff --git a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj index 79cbc8933e..3e6f22c4c5 100644 --- a/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj +++ b/OpenRA.Mods.Common/OpenRA.Mods.Common.csproj @@ -199,10 +199,7 @@ - - - @@ -218,11 +215,15 @@ + + + + @@ -357,9 +358,8 @@ - + - diff --git a/OpenRA.Mods.Common/Scripting/Global/EffectGlobal.cs b/OpenRA.Mods.Common/Scripting/Global/EffectGlobal.cs new file mode 100644 index 0000000000..e4669aade6 --- /dev/null +++ b/OpenRA.Mods.Common/Scripting/Global/EffectGlobal.cs @@ -0,0 +1,36 @@ +#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 OpenRA.Mods.Common.Traits; +using OpenRA.Scripting; + +namespace OpenRA.Mods.Common.Scripting +{ + [ScriptGlobal("Effect")] + public class EffectGlobal : ScriptGlobal + { + readonly IEnumerable fpes; + + public EffectGlobal(ScriptContext context) + : base(context) + { + fpes = context.World.WorldActor.TraitsImplementing(); + } + + [Desc("Controls the `FlashPaletteEffect` trait.")] + public void Flash(string type = null, int ticks = -1) + { + foreach (var fpe in fpes) + if (fpe.Info.Type == type) + fpe.Enable(ticks); + } + } +} diff --git a/OpenRA.Mods.Common/Scripting/Global/MediaGlobal.cs b/OpenRA.Mods.Common/Scripting/Global/MediaGlobal.cs index 5d476640df..bcc0d41058 100644 --- a/OpenRA.Mods.Common/Scripting/Global/MediaGlobal.cs +++ b/OpenRA.Mods.Common/Scripting/Global/MediaGlobal.cs @@ -45,6 +45,12 @@ namespace OpenRA.Mods.Common.Scripting Sound.PlayNotification(world.Map.Rules, player, "Sounds", notification, player != null ? player.Country.Race : null); } + [Desc("Play a sound file")] + public void PlaySound(string file) + { + Sound.Play(file); + } + MusicInfo previousMusic; Action onComplete; [Desc("Play track defined in music.yaml or keep it empty for a random song.")] diff --git a/OpenRA.Mods.Common/Traits/PaletteEffects/FlashPaletteEffect.cs b/OpenRA.Mods.Common/Traits/PaletteEffects/FlashPaletteEffect.cs new file mode 100644 index 0000000000..0b832e74d1 --- /dev/null +++ b/OpenRA.Mods.Common/Traits/PaletteEffects/FlashPaletteEffect.cs @@ -0,0 +1,81 @@ +#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 OpenRA.Graphics; +using OpenRA.Traits; + +namespace OpenRA.Mods.Common.Traits +{ + using GUtil = OpenRA.Graphics.Util; + + [Desc("Used for bursted one-colored whole screen effects. Add this to the world actor.")] + public class FlashPaletteEffectInfo : ITraitInfo + { + public readonly string[] ExcludePalettes = { "cursor", "chrome", "colorpicker", "fog", "shroud" }; + + [Desc("Measured in ticks.")] + public readonly int Length = 20; + + public readonly Color Color = Color.White; + + [Desc("Set this when using multiple independent flash effects.")] + public readonly string Type = null; + + public object Create(ActorInitializer init) { return new FlashPaletteEffect(this); } + } + + public class FlashPaletteEffect : IPaletteModifier, ITick + { + public readonly FlashPaletteEffectInfo Info; + + public FlashPaletteEffect(FlashPaletteEffectInfo info) + { + Info = info; + } + + int remainingFrames; + + public void Enable(int ticks) + { + if (ticks == -1) + remainingFrames = Info.Length; + else + remainingFrames = ticks; + } + + public void Tick(Actor self) + { + if (remainingFrames > 0) + remainingFrames--; + } + + public void AdjustPalette(IReadOnlyDictionary palettes) + { + if (remainingFrames == 0) + return; + + var frac = (float)remainingFrames / Info.Length; + + foreach (var pal in palettes) + { + for (var x = 0; x < Palette.Size; x++) + { + var orig = pal.Value.GetColor(x); + var c = Info.Color; + var color = Color.FromArgb(orig.A, ((int)c.R).Clamp(0, 255), ((int)c.G).Clamp(0, 255), ((int)c.B).Clamp(0, 255)); + var final = GUtil.PremultipliedColorLerp(frac, orig, GUtil.PremultiplyAlpha(Color.FromArgb(orig.A, color))); + pal.Value.SetColor(x, final); + } + } + } + } +} diff --git a/OpenRA.Mods.Common/Traits/PaletteEffects/NukePaletteEffect.cs b/OpenRA.Mods.Common/Traits/PaletteEffects/NukePaletteEffect.cs deleted file mode 100644 index 05199a1f97..0000000000 --- a/OpenRA.Mods.Common/Traits/PaletteEffects/NukePaletteEffect.cs +++ /dev/null @@ -1,57 +0,0 @@ -#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 OpenRA.Graphics; -using OpenRA.Traits; - -namespace OpenRA.Mods.Common.Traits -{ - using GUtil = OpenRA.Graphics.Util; - - [Desc("Apply palette full screen rotations during atom bomb explosions. Add this to the world actor.")] - class NukePaletteEffectInfo : TraitInfo { } - - public class NukePaletteEffect : IPaletteModifier, ITick - { - const int NukeEffectLength = 20; - int remainingFrames; - - public void Enable() - { - remainingFrames = NukeEffectLength; - } - - public void Tick(Actor self) - { - if (remainingFrames > 0) - remainingFrames--; - } - - public void AdjustPalette(IReadOnlyDictionary palettes) - { - if (remainingFrames == 0) - return; - - var frac = (float)remainingFrames / NukeEffectLength; - - foreach (var pal in palettes) - { - for (var x = 0; x < Palette.Size; x++) - { - var orig = pal.Value.GetColor(x); - var final = GUtil.PremultipliedColorLerp(frac, orig, GUtil.PremultiplyAlpha(Color.FromArgb(orig.A, Color.White))); - pal.Value.SetColor(x, final); - } - } - } - } -} diff --git a/OpenRA.Mods.Common/Traits/Player/MissionObjectives.cs b/OpenRA.Mods.Common/Traits/Player/MissionObjectives.cs index 6d7aa0a1d7..8e8082590f 100644 --- a/OpenRA.Mods.Common/Traits/Player/MissionObjectives.cs +++ b/OpenRA.Mods.Common/Traits/Player/MissionObjectives.cs @@ -250,13 +250,18 @@ namespace OpenRA.Mods.Common.Traits public class ObjectivesPanelInfo : ITraitInfo { public string PanelName = null; + + [Desc("in ms")] + public int ExitDelay = 1400; + public object Create(ActorInitializer init) { return new ObjectivesPanel(this); } } public class ObjectivesPanel : IObjectivesPanel { - ObjectivesPanelInfo info; + readonly ObjectivesPanelInfo info; public ObjectivesPanel(ObjectivesPanelInfo info) { this.info = info; } public string PanelName { get { return info.PanelName; } } + public int ExitDelay { get { return info.ExitDelay; } } } } diff --git a/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs b/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs index 967f8b9b2d..c8d971d457 100644 --- a/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs +++ b/OpenRA.Mods.Common/Traits/Sound/AmbientSound.cs @@ -24,10 +24,10 @@ namespace OpenRA.Mods.Common.Traits { public AmbientSound(Actor self, AmbientSoundInfo info) { - if (self == self.World.WorldActor) - Sound.PlayLooped(info.SoundFile); - else + if (self.HasTrait()) Sound.PlayLooped(info.SoundFile, self.CenterPosition); + else + Sound.PlayLooped(info.SoundFile); } } } diff --git a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs index 63cd0042ba..fee57d8000 100644 --- a/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs +++ b/OpenRA.Mods.Common/Traits/SupportPowers/NukePower.cs @@ -45,6 +45,8 @@ namespace OpenRA.Mods.Common.Traits [Desc("Amount of time after detonation to remove the camera")] public readonly int CameraRemoveDelay = 25; + public readonly string FlashType = null; + public override object Create(ActorInitializer init) { return new NukePower(init.Self, this); } } @@ -76,7 +78,8 @@ namespace OpenRA.Mods.Common.Traits var missile = new NukeLaunch(self.Owner, info.MissileWeapon, self.CenterPosition + body.LocalToWorld(info.SpawnOffset), targetPosition, - info.FlightVelocity, info.FlightDelay, info.SkipAscent); + info.FlightVelocity, info.FlightDelay, info.SkipAscent, + info.FlashType); self.World.AddFrameEndTask(w => w.Add(missile)); diff --git a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs index f2d2f23de9..21c1c678e7 100644 --- a/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs +++ b/OpenRA.Mods.Common/UtilityCommands/UpgradeRules.cs @@ -1353,6 +1353,13 @@ namespace OpenRA.Mods.Common.UtilityCommands } } + // Generalized the flash palette trait + if (engineVersion < 20150627) + { + if (node.Key == "NukePaletteEffect") + node.Key = "FlashPaletteEffect"; + } + UpgradeActorRules(engineVersion, ref node.Value.Nodes, node, depth + 1); } } diff --git a/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs index 4460f912de..2d7d1e8ece 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Ingame/IngameMenuLogic.cs @@ -9,8 +9,10 @@ #endregion using System; +using System.Linq; using OpenRA.Graphics; using OpenRA.Mods.Common.Traits; +using OpenRA.Traits; using OpenRA.Widgets; namespace OpenRA.Mods.Common.Widgets.Logic @@ -41,7 +43,8 @@ namespace OpenRA.Mods.Common.Widgets.Logic resumeDisabled = true; - var exitDelay = 1200; + var iop = world.WorldActor.TraitsImplementing().FirstOrDefault(); + var exitDelay = iop != null ? iop.ExitDelay : 0; if (mpe != null) { Game.RunAfterDelay(exitDelay, () => mpe.Fade(MenuPaletteEffect.EffectType.Black)); diff --git a/OpenRA.Mods.Common/Widgets/Logic/Ingame/LeaveMapLogic.cs b/OpenRA.Mods.Common/Widgets/Logic/Ingame/LeaveMapLogic.cs index eb6b21c99f..446fadfe43 100644 --- a/OpenRA.Mods.Common/Widgets/Logic/Ingame/LeaveMapLogic.cs +++ b/OpenRA.Mods.Common/Widgets/Logic/Ingame/LeaveMapLogic.cs @@ -106,7 +106,7 @@ namespace OpenRA.Mods.Common.Widgets Sound.PlayNotification(world.Map.Rules, null, "Speech", "Leave", world.LocalPlayer == null ? null : world.LocalPlayer.Country.Race); - var exitDelay = 1200; + var exitDelay = iop != null ? iop.ExitDelay : 0; if (mpe != null) { Game.RunAfterDelay(exitDelay, () => mpe.Fade(MenuPaletteEffect.EffectType.Black)); diff --git a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj index cc134e0f1f..762e4cfb6c 100644 --- a/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj +++ b/OpenRA.Mods.RA/OpenRA.Mods.RA.csproj @@ -103,6 +103,7 @@ + diff --git a/OpenRA.Mods.Common/Traits/PaletteEffects/LightPaletteRotator.cs b/OpenRA.Mods.RA/Traits/PaletteEffects/LightPaletteRotator.cs similarity index 97% rename from OpenRA.Mods.Common/Traits/PaletteEffects/LightPaletteRotator.cs rename to OpenRA.Mods.RA/Traits/PaletteEffects/LightPaletteRotator.cs index fca4ebb4e1..f9769c9606 100644 --- a/OpenRA.Mods.Common/Traits/PaletteEffects/LightPaletteRotator.cs +++ b/OpenRA.Mods.RA/Traits/PaletteEffects/LightPaletteRotator.cs @@ -13,7 +13,7 @@ using System.Linq; using OpenRA.Graphics; using OpenRA.Traits; -namespace OpenRA.Mods.Common.Traits +namespace OpenRA.Mods.RA.Traits { [Desc("Palette effect used for blinking \"animations\" on actors.")] class LightPaletteRotatorInfo : ITraitInfo diff --git a/mods/cnc/rules/palettes.yaml b/mods/cnc/rules/palettes.yaml index e6d4c8a4c7..ad0081679a 100644 --- a/mods/cnc/rules/palettes.yaml +++ b/mods/cnc/rules/palettes.yaml @@ -70,7 +70,7 @@ MenuPaletteEffect: MenuEffect: Desaturated CloakPaletteEffect: - NukePaletteEffect: + FlashPaletteEffect: WaterPaletteRotation: ExcludePalettes: effect diff --git a/mods/cnc/rules/world.yaml b/mods/cnc/rules/world.yaml index 3694600a82..f27ea40b00 100644 --- a/mods/cnc/rules/world.yaml +++ b/mods/cnc/rules/world.yaml @@ -54,7 +54,6 @@ World: PlayerCommands: HelpCommand: ScreenShaker: - NukePaletteEffect: BuildingInfluence: BridgeLayer: Bridges: bridge1, bridge2, bridge3, bridge4 diff --git a/mods/d2k/rules/palettes.yaml b/mods/d2k/rules/palettes.yaml index b32bb54553..159dd94f7e 100644 --- a/mods/d2k/rules/palettes.yaml +++ b/mods/d2k/rules/palettes.yaml @@ -86,5 +86,5 @@ Alpha: 0.68 Premultiply: false PlayerHighlightPalette: - NukePaletteEffect: + FlashPaletteEffect: diff --git a/mods/ra/bits/rain.aud b/mods/ra/bits/rain.aud new file mode 100644 index 0000000000..da8062df54 Binary files /dev/null and b/mods/ra/bits/rain.aud differ diff --git a/mods/ra/bits/thunder.aud b/mods/ra/bits/thunder.aud new file mode 100644 index 0000000000..aa629e90f0 Binary files /dev/null and b/mods/ra/bits/thunder.aud differ diff --git a/mods/ra/maps/fort-lonestar/fort-lonestar.lua b/mods/ra/maps/fort-lonestar/fort-lonestar.lua index ff91aac9ce..bbaf8a807a 100644 --- a/mods/ra/maps/fort-lonestar/fort-lonestar.lua +++ b/mods/ra/maps/fort-lonestar/fort-lonestar.lua @@ -147,6 +147,16 @@ SovietsRetreating = function() end) end +Tick = function() + if (Utils.RandomInteger(1, 200) == 10) then + local delay = Utils.RandomInteger(1, 10) + Effect.Flash("LightningStrike", delay) + Trigger.AfterDelay(delay, function() + Media.PlaySound("thunder.aud") + end) + end +end + WorldLoaded = function() soviets = Player.GetPlayer("Soviets") players = { } diff --git a/mods/ra/maps/fort-lonestar/map.yaml b/mods/ra/maps/fort-lonestar/map.yaml index 04b1f09955..9697d503f1 100644 --- a/mods/ra/maps/fort-lonestar/map.yaml +++ b/mods/ra/maps/fort-lonestar/map.yaml @@ -501,6 +501,15 @@ Rules: CrateActors: fortcrate -SpawnMPUnits: -MPStartLocations: + GlobalLightingPaletteEffect: + Red: 0.75 + Green: 0.85 + Blue: 1.5 + Ambient: 0.35 + AmbientSound: + SoundFile: rain.aud + FlashPaletteEffect@LIGHTNINGSTRIKE: + Type: LightningStrike LuaScript: Scripts: fort-lonestar.lua ScriptUpgradesCache: diff --git a/mods/ra/rules/palettes.yaml b/mods/ra/rules/palettes.yaml index fbdcc159e8..70eb65a5f2 100644 --- a/mods/ra/rules/palettes.yaml +++ b/mods/ra/rules/palettes.yaml @@ -70,5 +70,6 @@ LightPaletteRotator: ExcludePalettes: terrain, effect ChronoshiftPaletteEffect: - NukePaletteEffect: + FlashPaletteEffect@NUKE: + Type: Nuke diff --git a/mods/ra/rules/structures.yaml b/mods/ra/rules/structures.yaml index bd4f760f69..5436180498 100644 --- a/mods/ra/rules/structures.yaml +++ b/mods/ra/rules/structures.yaml @@ -38,6 +38,7 @@ MSLO: DisplayRadarPing: True BeaconPoster: atomicon CameraActor: camera + FlashType: Nuke CanPowerDown: RequiresPower: DisabledOverlay: