diff --git a/Assistant.Designer.cs b/Assistant.Designer.cs index 3a13928..3d7bf30 100644 --- a/Assistant.Designer.cs +++ b/Assistant.Designer.cs @@ -152,7 +152,7 @@ private void InitializeComponent() this.groupBoxBombState.Size = new System.Drawing.Size(256, 201); this.groupBoxBombState.TabIndex = 0; this.groupBoxBombState.TabStop = false; - this.groupBoxBombState.Text = "Bomb State"; + this.groupBoxBombState.Text = "Bomb Settings"; // // labelStrikes // @@ -270,7 +270,7 @@ private void InitializeComponent() this.labelVoice.Location = new System.Drawing.Point(7, 56); this.labelVoice.Margin = new Padding(4, 0, 4, 0); this.labelVoice.Name = "labelVoice"; - this.labelVoice.Size = new System.Drawing.Size(51, 13); + this.labelVoice.Size = new System.Drawing.Size(37, 13); this.labelVoice.TabIndex = 9; this.labelVoice.Text = "Voice:"; this.labelVoice.TextAlign = System.Drawing.ContentAlignment.MiddleLeft; diff --git a/Brain/Brain.cs b/Brain/Brain.cs index d036d2d..6df8076 100644 --- a/Brain/Brain.cs +++ b/Brain/Brain.cs @@ -145,11 +145,6 @@ private string ProcessGlobal(string command, Bomb bomb) private string ProcessModule(string command, Bomb bomb) { - if (!bomb.Ready) - { - return "Bomb not set up."; - } - string module = command[(command.IndexOf(' ') + 1) ..].ToUpperInvariant(); if (bomb.ActiveModule != null) @@ -157,15 +152,20 @@ private string ProcessModule(string command, Bomb bomb) this.ResetProcessors(); } - SpeechProcessor speechModule = this.processors[module]; + BombModule bombModule = this.processors[module] as BombModule; - if (!speechModule.IsGlobal) + if (!bombModule.IsGlobal) { - speechModule = Activator.CreateInstance(this.processors[module].GetType()) as SpeechProcessor; - this.processors[module] = speechModule; + bombModule = Activator.CreateInstance(this.processors[module].GetType()) as BombModule; + this.processors[module] = bombModule; + + if (!bombModule.TryDefuse(bomb, out string response)) + { + return response; + } } - bomb.ActiveModule = speechModule as BombModule; + bomb.ActiveModule = bombModule; this.Recognition.Grammars.Where(g => g.Name == module) .First() .Enabled = true; diff --git a/Game/Bomb.cs b/Game/Bomb.cs index f10e426..c69b01e 100644 --- a/Game/Bomb.cs +++ b/Game/Bomb.cs @@ -2,6 +2,7 @@ namespace KTANE.Game { using System; using System.Collections.Generic; + using System.ComponentModel; using System.Linq; using System.Speech.Recognition; using KTANE.Brain; @@ -25,16 +26,22 @@ internal class Bomb : SpeechProcessor public bool AutoReset { get; set; } + [DisplayName("Batteries")] public int? Batteries { get; set; } + [DisplayName("Parallel Port")] public bool? HasParallelPort { get; set; } + [DisplayName("FRK")] public bool? HasLitFRK { get; set; } + [DisplayName("CAR")] public bool? HasLitCAR { get; set; } + [DisplayName("Vowel")] public bool? HasVowel { get; set; } + [DisplayName("Last Digit")] public bool? LastDigitEven { get; set; } public int Strikes { get; set; } @@ -83,10 +90,6 @@ public override GrammarBuilder Grammar } } - public bool Ready => typeof(Bomb).GetProperties() - .Where(p => p.PropertyType.IsGenericType && p.PropertyType.GetGenericTypeDefinition() == typeof(Nullable<>)) - .All(p => p.GetValue(this) != null); - public static Bomb CreateRandom() { Random rng = new (); diff --git a/Game/BombModule.cs b/Game/BombModule.cs index e3a5bfd..85253d8 100644 --- a/Game/BombModule.cs +++ b/Game/BombModule.cs @@ -1,9 +1,36 @@ namespace KTANE.Game { + using System.Collections.Generic; + using System.ComponentModel; + using System.Linq; + using System.Reflection; using KTANE.Brain; internal abstract class BombModule : SpeechProcessor { public abstract string PreInfo { get; } + + public bool TryDefuse(Bomb bomb, out string response) + { + response = null; + + if (this.GetType() + .GetMethod(nameof(this.Process)) + .GetCustomAttribute(typeof(RequiredBombSettingAttribute), true) is RequiredBombSettingAttribute attr) + { + List missing = typeof(Bomb).GetProperties() + .Where(p => attr.Settings.Contains(p.Name) + && p.GetValue(bomb) == null) + .Select(p => (p.GetCustomAttribute(typeof(DisplayNameAttribute), false) as DisplayNameAttribute).DisplayName) + .ToList(); + + if (missing.Count > 0) + { + response = $"Set {string.Join(", ", missing)}!"; + } + } + + return response == null; + } } } \ No newline at end of file diff --git a/Game/Modules/Button.cs b/Game/Modules/Button.cs index 34b61be..4963ab5 100644 --- a/Game/Modules/Button.cs +++ b/Game/Modules/Button.cs @@ -36,6 +36,7 @@ public override GrammarBuilder Grammar public override string PreInfo => string.Empty; + [RequiredBombSetting(nameof(Bomb.Batteries), nameof(Bomb.HasLitCAR), nameof(Bomb.HasLitFRK))] public override string Process(string command, Bomb bomb) { string[] parts = command.Split(' '); diff --git a/Game/Modules/ComplexWires.cs b/Game/Modules/ComplexWires.cs index 911fa54..38a1f4c 100644 --- a/Game/Modules/ComplexWires.cs +++ b/Game/Modules/ComplexWires.cs @@ -46,6 +46,7 @@ public override GrammarBuilder Grammar } } + [RequiredBombSetting(nameof(Bomb.Batteries), nameof(Bomb.HasParallelPort), nameof(Bomb.LastDigitEven))] public override string Process(string command, Bomb bomb) { bool red = command.Contains("red"); diff --git a/Game/Modules/Wires.cs b/Game/Modules/Wires.cs index 2de0601..e3e2adb 100644 --- a/Game/Modules/Wires.cs +++ b/Game/Modules/Wires.cs @@ -23,6 +23,7 @@ public override GrammarBuilder Grammar } } + [RequiredBombSetting(nameof(Bomb.LastDigitEven))] public override string Process(string command, Bomb bomb) { string[] wires = command.Split(' '); diff --git a/Game/RequiredBombSettingAttribute.cs b/Game/RequiredBombSettingAttribute.cs new file mode 100644 index 0000000..483d162 --- /dev/null +++ b/Game/RequiredBombSettingAttribute.cs @@ -0,0 +1,17 @@ +namespace KTANE.Game +{ + using System; + using System.Collections.Generic; + using System.Linq; + + [AttributeUsage(AttributeTargets.Method)] + internal class RequiredBombSettingAttribute : Attribute + { + public RequiredBombSettingAttribute(params string[] settings) + { + this.Settings = settings.ToList(); + } + + public List Settings { get; private set; } + } +}