notifications (formerly EVAalerts) centralized and race specific

outsourced into notifications.yaml
triggered with PlayNotification(...)

(v2: less redundant code for PlayVoice/Notifications)

added harvester under attack and battlecontrol terminated
This commit is contained in:
Matthias Mailänder
2012-06-28 19:52:25 +02:00
committed by Chris Forbes
parent 5fee165692
commit 7a578a0679
40 changed files with 271 additions and 219 deletions

View File

@@ -20,7 +20,7 @@ namespace OpenRA.FileFormats
public readonly string[]
Mods, Folders, Packages, Rules, ServerTraits,
Sequences, Cursors, Chrome, Assemblies, ChromeLayout,
Weapons, Voices, Music, Movies, TileSets, ChromeMetrics;
Weapons, Voices, Notifications, Music, Movies, TileSets, ChromeMetrics;
public readonly MiniYaml LoadScreen;
public readonly Dictionary<string, Pair<string,int>> Fonts;
public readonly int TileSize = 24;
@@ -44,6 +44,7 @@ namespace OpenRA.FileFormats
ChromeLayout = YamlList(yaml, "ChromeLayout");
Weapons = YamlList(yaml, "Weapons");
Voices = YamlList(yaml, "Voices");
Notifications = YamlList(yaml, "Notifications");
Music = YamlList(yaml, "Music");
Movies = YamlList(yaml, "Movies");
TileSets = YamlList(yaml, "TileSets");

View File

@@ -20,7 +20,8 @@ namespace OpenRA
{
public static Dictionary<string, ActorInfo> Info;
public static Dictionary<string, WeaponInfo> Weapons;
public static Dictionary<string, VoiceInfo> Voices;
public static Dictionary<string, SoundInfo> Voices;
public static Dictionary<string, SoundInfo> Notifications;
public static Dictionary<string, MusicInfo> Music;
public static Dictionary<string, string> Movies;
public static Dictionary<string, TileSet> TileSets;
@@ -30,7 +31,8 @@ namespace OpenRA
// Added support to extend the list of rules (add it to m.LocalRules)
Info = LoadYamlRules(m.Rules, map.Rules, (k, y) => new ActorInfo(k.Key.ToLowerInvariant(), k.Value, y));
Weapons = LoadYamlRules(m.Weapons, map.Weapons, (k, _) => new WeaponInfo(k.Key.ToLowerInvariant(), k.Value));
Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new VoiceInfo(k.Value));
Voices = LoadYamlRules(m.Voices, map.Voices, (k, _) => new SoundInfo(k.Value));
Notifications = LoadYamlRules(m.Notifications, map.Notifications, (k, _) => new SoundInfo(k.Value));
Music = LoadYamlRules(m.Music, new List<MiniYamlNode>(), (k, _) => new MusicInfo(k.Key, k.Value));
Movies = LoadYamlRules(m.Movies, new List<MiniYamlNode>(), (k, v) => k.Value.Value);

View File

@@ -1,4 +1,4 @@
#region Copyright & License Information
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* This file is part of OpenRA, which is free software. It is made
@@ -15,11 +15,12 @@ using OpenRA.FileFormats;
namespace OpenRA.GameRules
{
public class VoiceInfo
public class SoundInfo
{
[FieldLoader.Ignore] public readonly Dictionary<string,string[]> Variants;
[FieldLoader.Ignore] public readonly Dictionary<string,string[]> Prefixes;
[FieldLoader.Ignore] public readonly Dictionary<string,string[]> Voices;
[FieldLoader.Ignore] public readonly Dictionary<string,string[]> Notifications;
public readonly string DefaultVariant = ".aud" ;
public readonly string DefaultPrefix = "" ;
public readonly string[] DisableVariants = { };
@@ -34,31 +35,28 @@ namespace OpenRA.GameRules
: new Dictionary<string, string[]>();
}
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, VoicePool>> Pools;
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, SoundPool>> VoicePools;
public readonly OpenRA.FileFormats.Lazy<Dictionary<string, SoundPool>> NotificationsPools;
public VoiceInfo( MiniYaml y )
public SoundInfo( MiniYaml y )
{
FieldLoader.Load( this, y );
Variants = Load(y, "Variants");
Prefixes = Load(y, "Prefixes");
Voices = Load(y, "Voices");
Notifications = Load(y, "Notifications");
if (!Voices.ContainsKey("Attack"))
Voices.Add("Attack", Voices["Move"]);
if (!Voices.ContainsKey("AttackMove"))
Voices.Add("AttackMove", Voices["Move"]);
Pools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new VoicePool(a.Value) ));
VoicePools = Lazy.New(() => Voices.ToDictionary( a => a.Key, a => new SoundPool(a.Value) ));
NotificationsPools = Lazy.New(() => Notifications.ToDictionary( a => a.Key, a => new SoundPool(a.Value) ));
}
}
public class VoicePool
public class SoundPool
{
readonly string[] clips;
readonly List<string> liveclips = new List<string>();
public VoicePool(params string[] clips)
public SoundPool(params string[] clips)
{
this.clips = clips;
}

View File

@@ -60,6 +60,7 @@ namespace OpenRA
[FieldLoader.Ignore] public List<MiniYamlNode> Sequences = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> Weapons = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> Voices = new List<MiniYamlNode>();
[FieldLoader.Ignore] public List<MiniYamlNode> Notifications = new List<MiniYamlNode>();
// Binary map data
[FieldLoader.Ignore] public byte TileFormat = 1;
@@ -150,6 +151,7 @@ namespace OpenRA
Sequences = NodesOrEmpty(yaml, "Sequences");
Weapons = NodesOrEmpty(yaml, "Weapons");
Voices = NodesOrEmpty(yaml, "Voices");
Notifications = NodesOrEmpty(yaml, "Notifications");
CustomTerrain = new string[MapSize.X, MapSize.Y];
@@ -204,6 +206,7 @@ namespace OpenRA
root.Add(new MiniYamlNode("Sequences", null, Sequences));
root.Add(new MiniYamlNode("Weapons", null, Weapons));
root.Add(new MiniYamlNode("Voices", null, Voices));
root.Add(new MiniYamlNode("Notifications", null, Notifications));
var entries = new Dictionary<string, byte[]>();
entries.Add("map.bin", SaveBinaryData());

View File

@@ -94,7 +94,7 @@
<Compile Include="GameRules\MusicInfo.cs" />
<Compile Include="GameRules\Rules.cs" />
<Compile Include="GameRules\Settings.cs" />
<Compile Include="GameRules\VoiceInfo.cs" />
<Compile Include="GameRules\SoundInfo.cs" />
<Compile Include="GameRules\WeaponInfo.cs" />
<Compile Include="Graphics\Animation.cs" />
<Compile Include="Graphics\AnimationWithOffset.cs" />

View File

@@ -90,11 +90,6 @@ namespace OpenRA
}
}
public void GiveAdvice(string advice)
{
Sound.PlayToPlayer(this, advice);
}
public Dictionary<Player, Stance> Stances = new Dictionary<Player, Stance>();
}
}

View File

@@ -246,7 +246,45 @@ namespace OpenRA
get { return (video != null) ? video.SeekPosition : 0; }
}
// Returns true if it played a phrase
// Returns true if played successfully
public static bool PlayPredefined(Player p, Actor voicedUnit, string type, string definition, string variant)
{
if (definition == null) return false;
var rules = (voicedUnit != null) ? Rules.Voices[type] : Rules.Notifications[type];
var ID = (voicedUnit != null) ? voicedUnit.ActorID : 0;
var clip = (voicedUnit != null) ? rules.VoicePools.Value[definition].GetNext() : rules.NotificationsPools.Value[definition].GetNext();
if (clip == null) return false;
var suffix = rules.DefaultVariant;
var prefix = rules.DefaultPrefix;
if (voicedUnit != null)
{
if (!rules.VoicePools.Value.ContainsKey("Attack"))
rules.VoicePools.Value.Add("Attack", rules.VoicePools.Value["Move"]);
if (!rules.VoicePools.Value.ContainsKey("AttackMove"))
rules.VoicePools.Value.Add("AttackMove", rules.VoicePools.Value["Move"]);
}
if (variant != null)
{
if (rules.Variants.ContainsKey(variant) && !rules.DisableVariants.Contains(definition))
suffix = rules.Variants[variant][ID % rules.Variants[variant].Length];
if (rules.Prefixes.ContainsKey(variant) && !rules.DisablePrefixes.Contains(definition))
prefix = rules.Prefixes[variant][ID % rules.Prefixes[variant].Length];
}
if (p == null)
Play(prefix + clip + suffix);
else
PlayToPlayer(p, prefix + clip + suffix);
return true;
}
public static bool PlayVoice(string phrase, Actor voicedUnit, string variant)
{
if (voicedUnit == null) return false;
@@ -256,21 +294,17 @@ namespace OpenRA
if (mi == null) return false;
if (mi.Voice == null) return false;
var vi = Rules.Voices[mi.Voice.ToLowerInvariant()];
var type = mi.Voice.ToLowerInvariant();
if (!vi.Pools.Value.ContainsKey(phrase))
return false;
return PlayPredefined(null, voicedUnit, type, phrase, variant);
}
var clip = vi.Pools.Value[phrase].GetNext();
if (clip == null)
return false;
public static bool PlayNotification(Player player, string type, string notification, string variant)
{
if (type == null) return false;
if (notification == null) return false;
var variantExt = (vi.Variants.ContainsKey(variant) && !vi.DisableVariants.Contains(phrase)) ?
vi.Variants[variant][voicedUnit.ActorID % vi.Variants[variant].Length] : vi.DefaultVariant;
var prefix = (vi.Prefixes.ContainsKey(variant) && !vi.DisablePrefixes.Contains(phrase)) ?
vi.Prefixes[variant][voicedUnit.ActorID % vi.Prefixes[variant].Length] : vi.DefaultPrefix;
Play(prefix + clip + variantExt);
return true;
return PlayPredefined(player, null, type.ToLowerInvariant(), notification, variant);
}
}

View File

@@ -1,43 +0,0 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 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
namespace OpenRA.Traits
{
public class EvaAlertsInfo : TraitInfo<EvaAlerts>
{
// Sound effects
public readonly string RadarUp = "radaron2.aud";
public readonly string RadarDown = "radardn1.aud";
public readonly string CashTickUp = "cashup1.aud";
public readonly string CashTickDown = "cashdn1.aud";
// Build Palette
public readonly string BuildingCannotPlaceAudio = "nodeply1.aud";
public readonly string NewOptions = "newopt1.aud";
// For manual powerup/down in ra-ng
public readonly string DisablePower = "bleep11.aud";
public readonly string EnablePower = "bleep12.aud";
// Eva speech
public readonly string Repairing = "repair1.aud";
public readonly string LowPower = "lopower1.aud";
public readonly string SilosNeeded = "silond1.aud";
public readonly string PrimaryBuildingSelected = "pribldg1.aud";
// Special powers
public readonly string AbilityInsufficientPower = "nopowr1.aud";
public readonly string LevelUp = "hydrod1.aud";
}
public class EvaAlerts {}
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2012 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,
@@ -136,8 +136,6 @@ namespace OpenRA.Traits
public void Tick(Actor self)
{
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
if(cashtickallowed > 0) {
cashtickallowed = cashtickallowed - 1;
}
@@ -152,7 +150,7 @@ namespace OpenRA.Traits
if (--nextSiloAdviceTime <= 0)
{
if (Ore > 0.8*OreCapacity)
Owner.GiveAdvice(eva.SilosNeeded);
Sound.PlayNotification(Owner, "Speech", "SilosNeeded", Owner.Country.Race);
nextSiloAdviceTime = AdviceInterval;
}
@@ -192,21 +190,19 @@ namespace OpenRA.Traits
public void playCashTickUp(Actor self)
{
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
if (Game.Settings.Sound.SoundCashTickType != SoundCashTicks.Disabled)
{
Sound.PlayToPlayer(self.Owner, eva.CashTickUp);
Sound.PlayNotification(self.Owner, "Sounds", "CashTickUp", self.Owner.Country.Race);
}
}
public void playCashTickDown(Actor self)
{
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
if (
Game.Settings.Sound.SoundCashTickType == SoundCashTicks.Extreme ||
(Game.Settings.Sound.SoundCashTickType == SoundCashTicks.Normal && cashtickallowed == 0)
) {
Sound.PlayToPlayer(self.Owner, eva.CashTickDown);
Sound.PlayNotification(self.Owner, "Sounds", "CashTickDown", self.Owner.Country.Race);
cashtickallowed = 3;
}

View File

@@ -54,6 +54,7 @@ namespace OpenRA.Traits
public interface IResolveOrder { void ResolveOrder(Actor self, Order order); }
public interface IValidateOrder { bool OrderValidation(OrderManager orderManager, World world, int clientId, Order order); }
public interface IOrderVoice { string VoicePhraseForOrder(Actor self, Order order); }
public interface INotify { void Play(Player p, string notification); }
public interface INotifySold { void Selling(Actor self); void Sold(Actor self); }
public interface INotifyDamage { void Damaged(Actor self, AttackInfo e); }
public interface INotifyDamageStateChanged { void DamageStateChanged(Actor self, AttackInfo e); }

View File

@@ -22,8 +22,6 @@ namespace OpenRA.Widgets
public bool Depressed = false;
public int VisualHeight = ChromeMetrics.Get<int>("ButtonDepth");
public string Font = ChromeMetrics.Get<string>("ButtonFont");
public string ClickSound = null;
public string ClickDisabledSound = null;
public bool Disabled = false;
public Func<string> GetText;
public Func<bool> IsDisabled;
@@ -73,10 +71,10 @@ namespace OpenRA.Widgets
if (!IsDisabled())
{
OnKeyPress(e);
Sound.Play(ClickSound);
Sound.PlayNotification(null, "Sounds", "ClickSound", null);
}
else
Sound.Play(ClickDisabledSound);
Sound.PlayNotification(null, "Sounds", "ClickDisabledSound", null);
return true;
}
@@ -105,12 +103,12 @@ namespace OpenRA.Widgets
{
OnMouseDown(mi);
Depressed = true;
Sound.Play(ClickSound);
Sound.PlayNotification(null, "Sounds", "ClickSound", null);
}
else
{
LoseFocus(mi);
Sound.Play(ClickDisabledSound);
Sound.PlayNotification(null, "Sounds", "ClickDisabledSound", null);
}
}
else if (mi.Event == MouseInputEvent.Move && Focused)

View File

@@ -121,7 +121,7 @@ namespace OpenRA
return selectable != null && selectable.Voice != null;
}
public static VoiceInfo GetVoice(this Actor a)
public static SoundInfo GetVoice(this Actor a)
{
var selectable = a.Info.Traits.GetOrDefault<SelectableInfo>();
if (selectable == null) return null;

View File

@@ -35,7 +35,7 @@ namespace OpenRA.Mods.Cnc.Widgets.Logic
// TODO: Create a mechanism to do things like this cleaner. Also needed for scripted missions
Action onQuit = () =>
{
Sound.Play("batlcon1.aud");
Sound.PlayNotification(null, "Speech", "Leave", null);
resumeDisabled = true;
Game.RunAfterDelay(1200, () => mpe.Fade(CncMenuPaletteEffect.EffectType.Black));
Game.RunAfterDelay(1200 + 40 * mpe.Info.FadeLength, () =>

View File

@@ -61,8 +61,6 @@ namespace OpenRA.Mods.Cnc.Widgets
class ProductionTabsWidget : Widget
{
public readonly string PaletteWidget = null;
public readonly string ClickSound = null;
public readonly string DisabledClickSound = null;
public readonly float ScrollVelocity = 4f;
public readonly int TabWidth = 30;
public readonly int ArrowWidth = 20;
@@ -248,9 +246,9 @@ namespace OpenRA.Mods.Cnc.Widgets
if (leftPressed || rightPressed)
{
if ((leftPressed && !leftDisabled) || (rightPressed && !rightDisabled))
Sound.Play(ClickSound);
Sound.PlayNotification(null, "Sounds", "ClickSound", null);
else
Sound.Play(DisabledClickSound);
Sound.PlayNotification(null, "Sounds", "DisabledClickSound", null);
}
// Check production tabs
@@ -258,7 +256,7 @@ namespace OpenRA.Mods.Cnc.Widgets
if (offsetloc.X > 0 && offsetloc.X < ContentWidth)
{
CurrentQueue = Groups[queueGroup].Tabs[offsetloc.X/(TabWidth - 1)].Queue;
Sound.Play(ClickSound);
Sound.PlayNotification(null, "Sounds", "ClickSound", null);
return true;
}
@@ -270,7 +268,7 @@ namespace OpenRA.Mods.Cnc.Widgets
if (e.Event != KeyInputEvent.Down) return false;
if (e.KeyName == "tab")
{
Sound.Play(ClickSound);
Sound.PlayNotification(null, "Sounds", "ClickSound", null);
SelectNextTab(e.Modifiers.HasModifier(Modifiers.Shift));
return true;
}

View File

@@ -37,9 +37,7 @@ namespace OpenRA.Mods.RA.Buildings
if (order.OrderString == "PowerDown")
{
disabled = !disabled;
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.PlayToPlayer(self.Owner, disabled ? eva.EnablePower : eva.DisablePower);
Sound.PlayNotification(self.Owner, "Sounds", (disabled ? "EnablePower" : "DisablePower"), self.Owner.Country.Race);
PowerManager.UpdateActor(self, disabled ? 0 : normalPower);
if (disabled)

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2012 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,
@@ -108,8 +108,7 @@ namespace OpenRA.Mods.RA.Buildings
if (--nextPowerAdviceTime <= 0)
{
if (lowPower)
Player.GiveAdvice(Rules.Info["world"].Traits.Get<EvaAlertsInfo>().LowPower);
Sound.PlayNotification(self.Owner, "Speech", "LowPower", self.Owner.Country.Race);
nextPowerAdviceTime = Info.AdviceInterval;
}
}

View File

@@ -48,7 +48,7 @@ namespace OpenRA.Mods.RA.Buildings
else
{
Repairer = p;
Sound.PlayToPlayer(Repairer, p.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>().Repairing);
Sound.PlayNotification(Repairer, "Speech", "Repairing", self.Owner.Country.Race);
self.World.AddFrameEndTask(
w => w.Add(new RepairIndicator(self, p)));

View File

@@ -15,10 +15,7 @@ namespace OpenRA.Mods.RA
{
public class ConquestVictoryConditionsInfo : ITraitInfo
{
public string WinNotification = null;
public string LoseNotification = null;
public int NotificationDelay = 1500; // Milliseconds
public readonly string Race = null;
public object Create(ActorInitializer init) { return new ConquestVictoryConditions(this); }
}
@@ -55,7 +52,6 @@ namespace OpenRA.Mods.RA
public void Lose(Actor self)
{
if (Info.Race != null && Info.Race != self.Owner.Country.Race) return;
if (self.Owner.WinState == WinState.Lost) return;
self.Owner.WinState = WinState.Lost;
@@ -70,14 +66,13 @@ namespace OpenRA.Mods.RA
Game.RunAfterDelay(Info.NotificationDelay, () =>
{
if (Game.IsCurrentWorld(self.World))
Sound.Play(Info.LoseNotification);
Sound.PlayNotification(self.Owner, "Speech", "Lose", self.Owner.Country.Race);
});
}
}
public void Win(Actor self)
{
if (Info.Race != null && Info.Race != self.Owner.Country.Race) return;
if (self.Owner.WinState == WinState.Won) return;
self.Owner.WinState = WinState.Won;
@@ -85,7 +80,7 @@ namespace OpenRA.Mods.RA
if (self.Owner == self.World.LocalPlayer)
{
self.World.LocalShroud.Disabled = true;
Game.RunAfterDelay(Info.NotificationDelay, () => Sound.Play(Info.WinNotification));
Game.RunAfterDelay(Info.NotificationDelay, () => Sound.PlayNotification(self.Owner, "Speech", "Win", self.Owner.Country.Race));
}
}
}

View File

@@ -77,8 +77,7 @@ namespace OpenRA.Mods.RA
while (Level < MaxLevel && Experience >= Levels[Level])
{
Level++;
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.PlayToPlayer(self.Owner, eva.LevelUp, self.CenterLocation);
Sound.PlayNotification(self.Owner, "Sounds", "LevelUp", self.Owner.Country.Race);
self.World.AddFrameEndTask(w => w.Add(new CrateEffect(self, "levelup", new int2(0,-24))));
}
}

View File

@@ -58,8 +58,7 @@ namespace OpenRA.Mods.RA.Orders
if (!world.CanPlaceBuilding( Building, BuildingInfo, topLeft, null)
|| !BuildingInfo.IsCloseEnoughToBase(world, Producer.Owner, Building, topLeft))
{
var eva = world.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.Play(eva.BuildingCannotPlaceAudio);
Sound.PlayNotification(Producer.Owner, "Speech", "BuildingCannotPlaceAudio", Producer.Owner.Country.Race);
yield break;
}

View File

@@ -1,6 +1,6 @@
#region Copyright & License Information
/*
* Copyright 2007-2011 The OpenRA Developers (see AUTHORS)
* Copyright 2007-2012 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,
@@ -17,9 +17,7 @@ namespace OpenRA.Mods.RA
{
public class BaseAttackNotifierInfo : ITraitInfo
{
public readonly int NotifyInterval = 30; /* seconds */
public readonly string Audio = "baseatk1.aud";
public readonly string Race = null;
public readonly int NotifyInterval = 30; // seconds
public object Create(ActorInitializer init) { return new BaseAttackNotifier(this); }
}
@@ -35,17 +33,16 @@ namespace OpenRA.Mods.RA
public void Damaged(Actor self, AttackInfo e)
{
if (info.Race != null && info.Race != self.Owner.Country.Race) return;
/* only track last hit against our base */
// only track last hit against our base
if (!self.HasTrait<Building>())
return;
/* don't track self-damage */
// don't track self-damage
if (e.Attacker != null && e.Attacker.Owner == self.Owner)
return;
if (self.World.FrameNumber - lastAttackTime > info.NotifyInterval * 25)
Sound.PlayToPlayer(self.Owner, info.Audio);
Sound.PlayNotification(self.Owner, "Speech", "BaseAttack", self.Owner.Country.Race);
lastAttackLocation = self.CenterLocation.ToCPos();
lastAttackTime = self.World.FrameNumber;

View File

@@ -0,0 +1,52 @@
#region Copyright & License Information
/*
* Copyright 2007-2012 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;
using OpenRA.Mods.RA.Buildings;
using OpenRA.Mods.RA.Effects;
using OpenRA.Traits;
namespace OpenRA.Mods.RA
{
public class HarvesterAttackNotifierInfo : ITraitInfo
{
public readonly int NotifyInterval = 30; // seconds
public object Create(ActorInitializer init) { return new HarvesterAttackNotifier(this); }
}
public class HarvesterAttackNotifier : INotifyDamage
{
HarvesterAttackNotifierInfo info;
public int lastAttackTime = -1;
public CPos lastAttackLocation;
public HarvesterAttackNotifier(HarvesterAttackNotifierInfo info) { this.info = info; }
public void Damaged(Actor self, AttackInfo e)
{
// only track last hit against our base
if (!self.HasTrait<Harvester>())
return;
// don't track self-damage
if (e.Attacker != null && e.Attacker.Owner == self.Owner)
return;
if (self.World.FrameNumber - lastAttackTime > info.NotifyInterval * 25)
Sound.PlayNotification(self.Owner, "Speech", "HarvesterAttack", self.Owner.Country.Race);
lastAttackLocation = self.CenterLocation.ToCPos();
lastAttackTime = self.World.FrameNumber;
}
}
}

View File

@@ -82,8 +82,7 @@ namespace OpenRA.Mods.RA
if (GetNumBuildables(self.Owner) > prevItems)
w.Add(new DelayedAction(10,
() => Sound.PlayToPlayer(order.Player,
w.WorldActor.Info.Traits.Get<EvaAlertsInfo>().NewOptions)));
() => Sound.PlayNotification(order.Player, "Speech", "NewOptions", order.Player.Country.Race)));
});
}
}

View File

@@ -66,8 +66,7 @@ namespace OpenRA.Mods.RA
isPrimary = true;
var eva = self.World.WorldActor.Info.Traits.Get<EvaAlertsInfo>();
Sound.PlayToPlayer(self.Owner, eva.PrimaryBuildingSelected);
Sound.PlayNotification(self.Owner, "Speech", "PrimaryBuildingSelected", self.Owner.Country.Race);
}
}

View File

@@ -44,9 +44,6 @@ namespace OpenRA.Mods.RA.Widgets
List<Pair<Rectangle, Action<MouseInput>>> tabs = new List<Pair<Rectangle, Action<MouseInput>>>();
Animation cantBuild;
Animation clock;
public readonly string BuildPaletteOpen = "bleep13.aud";
public readonly string BuildPaletteClose = "bleep13.aud";
public readonly string TabClick = "ramenu1.aud";
readonly WorldRenderer worldRenderer;
readonly World world;
@@ -118,11 +115,11 @@ namespace OpenRA.Mods.RA.Widgets
// Play palette-open sound at the start of the activate anim (open)
if (paletteAnimationFrame == 1 && paletteOpen)
Sound.Play(BuildPaletteOpen);
Sound.PlayNotification(null, "Sounds", "BuildPaletteOpen", null);
// Play palette-close sound at the start of the activate anim (close)
if (paletteAnimationFrame == paletteAnimationLength + -1 && !paletteOpen)
Sound.Play(BuildPaletteClose);
Sound.PlayNotification(null, "Sounds", "BuildPaletteClose", null);
// Animation is complete
if ((paletteAnimationFrame == 0 && !paletteOpen)
@@ -291,7 +288,7 @@ namespace OpenRA.Mods.RA.Widgets
Action<MouseInput> HandleClick(string name, World world)
{
return mi => {
Sound.Play(TabClick);
Sound.PlayNotification(null, "Sounds", "TabClick", null);
if (name != null)
HandleBuildPalette(world, name, (mi.Button == MouseButton.Left));
@@ -304,7 +301,7 @@ namespace OpenRA.Mods.RA.Widgets
if (mi.Button != MouseButton.Left)
return;
Sound.Play(TabClick);
Sound.PlayNotification(null, "Sounds", "TabClick", null);
var wasOpen = paletteOpen;
paletteOpen = (CurrentQueue == queue && wasOpen) ? false : true;
CurrentQueue = queue;
@@ -496,7 +493,7 @@ namespace OpenRA.Mods.RA.Widgets
if ( toBuild != null )
{
Sound.Play(TabClick);
Sound.PlayNotification(null, "Sounds", "TabClick", null);
HandleBuildPalette(world, toBuild.Name, true);
return true;
}

View File

@@ -38,7 +38,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
};
cheatsButton.IsVisible = () => world.LocalPlayer != null && world.LobbyInfo.GlobalSettings.AllowCheats;
optionsBG.Get<ButtonWidget>("DISCONNECT").OnClick = () => LeaveGame(optionsBG);
optionsBG.Get<ButtonWidget>("DISCONNECT").OnClick = () => LeaveGame(optionsBG, world);
optionsBG.Get<ButtonWidget>("SETTINGS").OnClick = () => Ui.OpenWindow("SETTINGS_MENU");
optionsBG.Get<ButtonWidget>("MUSIC").OnClick = () => Ui.OpenWindow("MUSIC_MENU");
@@ -57,7 +57,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
var postGameObserve = postgameBG.Get<ButtonWidget>("POSTGAME_OBSERVE");
var postgameQuit = postgameBG.Get<ButtonWidget>("POSTGAME_QUIT");
postgameQuit.OnClick = () => LeaveGame(postgameQuit);
postgameQuit.OnClick = () => LeaveGame(postgameQuit, world);
postGameObserve.OnClick = () => postgameQuit.Visible = false;
postGameObserve.IsVisible = () => world.LocalPlayer.WinState != WinState.Won;
@@ -76,8 +76,9 @@ namespace OpenRA.Mods.RA.Widgets.Logic
};
}
void LeaveGame(Widget pane)
void LeaveGame(Widget pane, World world)
{
Sound.PlayNotification(null, "Speech", "Leave", world.LocalPlayer.Country.Race);
pane.Visible = false;
Game.Disconnect();
Game.LoadShellMap();

View File

@@ -237,7 +237,7 @@ namespace OpenRA.Mods.RA.Widgets.Logic
chatPanel.AddChild(template);
chatPanel.ScrollToBottom();
Sound.Play("scold1.aud");
Sound.PlayNotification(null, "Sounds", "ChatLine", null);
}
void UpdateCurrentMap()

View File

@@ -175,8 +175,7 @@ namespace OpenRA.Mods.RA.Widgets
if (hasRadarNew != hasRadar)
{
radarAnimating = true;
var eva = Rules.Info["world"].Traits.Get<EvaAlertsInfo>();
Sound.Play(hasRadarNew ? eva.RadarUp : eva.RadarDown);
Sound.PlayNotification(null, "Sounds", (hasRadarNew ? "RadarUp" : "RadarDown"), null);
}
hasRadar = hasRadarNew;

View File

@@ -103,8 +103,6 @@ Container@PLAYER_WIDGETS:
Font:Bold
TooltipText: Menu
TooltipContainer:TOOLTIP_CONTAINER
ClickSound:button.aud
ClickDisabledSound:scold2.aud
Children:
Image@ICON:
X:7
@@ -120,8 +118,6 @@ Container@PLAYER_WIDGETS:
Font:Bold
TooltipText: Sell
TooltipContainer:TOOLTIP_CONTAINER
ClickSound:button.aud
ClickDisabledSound:scold2.aud
Children:
Image@ICON:
X:7
@@ -136,8 +132,6 @@ Container@PLAYER_WIDGETS:
Font:Bold
TooltipText: Repair
TooltipContainer:TOOLTIP_CONTAINER
ClickSound:button.aud
ClickDisabledSound:scold2.aud
Children:
Image@ICON:
X:7
@@ -200,8 +194,6 @@ Container@PLAYER_WIDGETS:
Key: q
TooltipText: Buildings
TooltipContainer:TOOLTIP_CONTAINER
ClickSound:button.aud
ClickDisabledSound:scold2.aud
Children:
Image@ICON:
X:7
@@ -214,8 +206,6 @@ Container@PLAYER_WIDGETS:
Key: w
TooltipText: Defense
TooltipContainer:TOOLTIP_CONTAINER
ClickSound:button.aud
ClickDisabledSound:scold2.aud
Children:
Image@ICON:
X:7
@@ -228,8 +218,6 @@ Container@PLAYER_WIDGETS:
Key: e
TooltipText: Infantry
TooltipContainer:TOOLTIP_CONTAINER
ClickSound:button.aud
ClickDisabledSound:scold2.aud
Children:
Image@ICON:
X:7
@@ -242,8 +230,6 @@ Container@PLAYER_WIDGETS:
Key: r
TooltipText: Vehicles
TooltipContainer:TOOLTIP_CONTAINER
ClickSound:button.aud
ClickDisabledSound:scold2.aud
Children:
Image@ICON:
X:7
@@ -256,8 +242,6 @@ Container@PLAYER_WIDGETS:
Key: t
TooltipText: Aircraft
TooltipContainer:TOOLTIP_CONTAINER
ClickSound:button.aud
ClickDisabledSound:scold2.aud
Children:
Image@ICON:
X:7
@@ -265,8 +249,6 @@ Container@PLAYER_WIDGETS:
ImageCollection:production-icons
ProductionTabs@PRODUCTION_TABS:
PaletteWidget:PRODUCTION_PALETTE
ClickSound:button.aud
DisabledClickSound:scold2.aud
X:WINDOW_RIGHT - 204
Y:268
Width:194
@@ -274,8 +256,6 @@ Container@PLAYER_WIDGETS:
ProductionPalette@PRODUCTION_PALETTE:
X:WINDOW_RIGHT - 204
Y:287
TabClick: button.aud
DisabledTabClick:scold2.aud
TooltipContainer:TOOLTIP_CONTAINER
Background@FMVPLAYER:
Width:WINDOW_RIGHT

View File

@@ -90,6 +90,9 @@ Movies:
Voices:
mods/cnc/voices.yaml
Notifications:
mods/cnc/notifications.yaml
Music:
mods/cnc/music.yaml

View File

@@ -0,0 +1,26 @@
Speech:
Notifications:
Repairing: repair1
LowPower: lopower1
SilosNeeded: silos1
PrimaryBuildingSelected: pribldg1
BuildingCannotPlaceAudio: deploy1
NewOptions: newopt1
AbilityInsufficientPower: nopower1
Win: accom1
Lose: fail1
BaseAttack: baseatk1
HarvesterAttack:
Leave: batlcon1
Sounds:
Notifications:
RadarUp: comcntr1
RadarDown: powrdn1
CashTickUp:
CashTickDown:
LevelUp: text2
ChatLine: scold1
TabClick: button
ClickSound: button
ClickDisabledSound: scold2

View File

@@ -3,8 +3,6 @@ Player:
TechTree:
SupportPowerManager:
ConquestVictoryConditions:
WinNotification:accom1.aud
LoseNotification:fail1.aud
PowerManager:
AllyRepair:
PlayerResources:
@@ -151,17 +149,6 @@ World:
CreateMPPlayers:
SpawnMPUnits:
MPStartLocations:
EvaAlerts:
RadarUp: comcntr1.aud
RadarDown: powrdn1.aud
BuildingCannotPlaceAudio: deploy1.aud
CashTickUp:
CashTickDown:
LowPower: lopower1.aud
SilosNeeded: silos1.aud
PrimaryBuildingSelected: pribldg1.aud
AbilityInsufficientPower: nopower1.aud
LevelUp: text2.aud
SpatialBins:
BinSize: 4
Shroud:

View File

@@ -13,14 +13,12 @@
# add more spice tiles and make them fit
# add game logic for concrete plates (use terrain overlay from bridges/ressources)
# allow placing turrets on walls
# R8 converter needs infantry/ornithocopter frame resorter
# add grenade thrower
# make sandworm behave like a moving anti-vehicle mine
# add neutral buildings: emperor palace, fremen siech, smugglers factory
# add deathhand missile (nuke)
# maybe add ornithocopter strikes (they are currently directly contrallable units with non-reloading machine guns as in Dune II)
# allow upgrades
# allow different EVA voices for each faction (currently Atreides only)
# add muzzles and explosions (currently falls back to RA)
# create a shellmap (currently just a blank placeholder)
# rework chrome UI, dialoges, tabs
@@ -32,4 +30,6 @@
# support patch 1.06 gamefiles: DATA.R8 has more frames and currently fails to extract, also featuring new terrain with white houses and new unit: grenade thrower
# infantry-only areas (Rough) do not show the dark-green mouse cursor
# put TilesetBuilder.Export into OpenRA.Utility to call the functions directly when extracting game-files (instead of opening a GUI)
# group number metrics are off
# group number metrics are off
# add bibs
# building offsets wrong (worst for towers)

View File

@@ -71,6 +71,9 @@ Weapons:
Voices:
mods/d2k/voices.yaml
Notifications:
mods/d2k/notifications.yaml
TileSets:
mods/d2k/tilesets/arrakis.yaml

View File

@@ -0,0 +1,37 @@
# requires Dune 2000/DATA/GAMESFX copied to ~/.openra/Content/d2k
Speech:
DefaultVariant: .AUD
Prefixes:
atreides: AI_
ordos: OI_
harkonnen: HI_
Notifications:
Repairing: MEND
BuildingCannotPlaceAudio: PLACE
LowPower: POWER
SilosNeeded: SILOS
PrimaryBuildingSelected: PRMRY
AbilityInsufficientPower:
NewOptions: NEWOP
Win: MWIN
Lose: MFAIL
BaseAttack: ATACK
HarvesterAttack: HATTK
Leave: ABORT
Sounds:
Notifications:
RadarUp: MULTI1
RadarDown:
DisablePower: POWRDN1
EnablePower: POWRUP1
CashTickUp: CASHTIK1
CashTickDown:CASHTIK1
LevelUp: SCORTIK1
ChatLine: CHAT1
BuildPaletteOpen: BUTTON1
BuildPaletteClose: BUTTON1
TabClick: SIDEBAR1
ClickSound: BUTTON1
ClickDisabledSound: ENDLIST1

View File

@@ -2,18 +2,7 @@ Player:
TechTree:
PlaceBuilding:
SupportPowerManager:
ConquestVictoryConditions@Atreides:
Race: atreides
WinNotification: AI_MWIN.AUD
LoseNotification: AI_MFAIL.AUD
ConquestVictoryConditions@Harkonnen:
Race: harkonnen
WinNotification: HI_MWIN.AUD
LoseNotification: HI_MFAIL.AUD
ConquestVictoryConditions@Ordos:
Race: ordos
WinNotification: OI_MWIN.AUD
LoseNotification: OI_MFAIL.AUD
ConquestVictoryConditions:
PowerManager:
AllyRepair:
PlayerResources:
@@ -65,15 +54,8 @@ Player:
PlayerColorPalette:
BasePalette: d2k
RemapIndex: 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255
BaseAttackNotifier@Atreides:
Race: atreides
Audio: AI_ATACK.AUD
BaseAttackNotifier@Harkonnen:
Race: harkonnen
Audio: HI_ATACK.AUD
BaseAttackNotifier@Ordos:
Race: ordos
Audio: OI_ATACK.AUD
BaseAttackNotifier:
HarvesterAttackNotifier:
World:
OpenWidgetAtGameStart:
@@ -179,25 +161,12 @@ World:
SpawnMPUnits@ordos:
InitialUnit: mcvo
Faction: ordos
#TODO: These are just the Atreides sounds.
EvaAlerts:
RadarUp: POWRUP1.aud
RadarDown: POWRDN1.aud
BuildingCannotPlaceAudio: AI_PLACE.AUD
CashTickUp: CASHTIK1.aud
CashTickDown:CASHTIK1.aud
NewOptions: AI_NEWOP.AUD
LowPower: AI_POWER.AUD
SilosNeeded: AI_SILOS.AUD
PrimaryBuildingSelected: AI_PRMRY.AUD
AbilityInsufficientPower:
LevelUp: SCORTIK1.aud
Repairing:
SpatialBins:
BinSize: 4
Shroud:
PathFinder:
ValidateOrder:
CRATE:
Tooltip:
Name: Crate

View File

@@ -46,7 +46,7 @@ HARVESTER:
Capacity: 20
Resources: Spice
UnloadTicksPerBale: 1
# How far away from our linked proc (refinery) to find resources (in cells):
# How far away from our linked refinery to find resources (in cells):
SearchFromProcRadius: 24
# How far away from last harvest order location to find more resources (in cells):
SearchFromOrderRadius: 12

View File

@@ -70,6 +70,9 @@ Weapons:
Voices:
mods/ra/voices.yaml
Notifications:
mods/ra/notifications.yaml
TileSets:
mods/ra/tilesets/snow.yaml

View File

@@ -0,0 +1,30 @@
Speech:
Notifications:
Repairing: repair1
LowPower: lopower1
SilosNeeded: silond1
PrimaryBuildingSelected: pribldg1
BuildingCannotPlaceAudio: nodeply1
NewOptions: newopt1
AbilityInsufficientPower: nopowr1
Win: misnwon1
Lose: misnlst1
BaseAttack: baseatk1
HarvesterAttack:
Leave: bct1
Sounds:
Notifications:
RadarUp: radaron2
RadarDown: radardn1
CashTickUp: cashup1
CashTickDown:cashdn1
LevelUp: hydrod1
DisablePower: bleep11
EnablePower: bleep12
ChatLine: scold1
BuildPaletteOpen: bleep13
BuildPaletteClose: bleep13
TabClick: ramenu1
ClickSound:
ClickDisabledSound:

View File

@@ -31,8 +31,6 @@ Player:
PlaceBuilding:
SupportPowerManager:
ConquestVictoryConditions:
WinNotification:misnwon1.aud
LoseNotification:misnlst1.aud
PowerManager:
AllyRepair:
PlayerResources:
@@ -293,7 +291,6 @@ World:
CreateMPPlayers:
MPStartLocations:
SpawnMPUnits:
EvaAlerts:
SpatialBins:
BinSize: 4
Shroud: