diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index 0547103b..6473877e 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -79,15 +79,14 @@ namespace SuperStarTrek _galaxy = new Galaxy(); _initialKlingonCount = _galaxy.KlingonCount; - _enterprise = new Enterprise(3000, random.GetCoordinate(), _output); + _enterprise = new Enterprise(3000, random.GetCoordinate(), _output, random); _enterprise .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) .Add(new LongRangeSensors(_galaxy, _output)) + .Add(new PhotonTubes(10, _enterprise, _output, _input)) .Add(new ShieldControl(_enterprise, _output, _input)) .Add(new DamageControl(_enterprise, _output)); - var quadrant = new Quadrant(_galaxy[_currentQuadrant], _enterprise); - _output.Write(Strings.Enterprise); _output.Write( Strings.Orders, @@ -100,6 +99,7 @@ namespace SuperStarTrek _input.WaitForAnyKeyButEnter("when ready to accept command"); + var quadrant = _galaxy[_currentQuadrant].BuildQuadrant(_enterprise, random, _galaxy); _enterprise.Enter(quadrant, Strings.StartText); } diff --git a/84 Super Star Trek/csharp/Input.cs b/84 Super Star Trek/csharp/Input.cs index 0fba2e4c..c632007f 100644 --- a/84 Super Star Trek/csharp/Input.cs +++ b/84 Super Star Trek/csharp/Input.cs @@ -27,14 +27,14 @@ namespace SuperStarTrek return Console.ReadLine(); } - public double GetNumber(string prompt) + public float GetNumber(string prompt) { _output.Prompt(prompt); while (true) { var response = Console.ReadLine(); - if (double.TryParse(response, out var value)) + if (float.TryParse(response, out var value)) { return value; } @@ -44,7 +44,7 @@ namespace SuperStarTrek } } - public bool TryGetNumber(string prompt, double minValue, double maxValue, out double value) + public bool TryGetNumber(string prompt, float minValue, float maxValue, out float value) { value = GetNumber($"{prompt} ({minValue}-{maxValue})"); diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index 97e5e3cd..ddaa10a9 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -15,9 +15,10 @@ namespace SuperStarTrek.Objects private readonly Output _output; private readonly List _systems; private readonly Dictionary _commandExecutors; + private readonly Random _random; private Quadrant _quadrant; - public Enterprise(int maxEnergy, Coordinates sector, Output output) + public Enterprise(int maxEnergy, Coordinates sector, Output output, Random random) { Sector = sector; TotalEnergy = _maxEnergy = maxEnergy; @@ -25,6 +26,7 @@ namespace SuperStarTrek.Objects _systems = new List(); _commandExecutors = new Dictionary(); _output = output; + _random = random; } public Coordinates Quadrant => _quadrant.Coordinates; @@ -88,5 +90,37 @@ namespace SuperStarTrek.Objects } public override string ToString() => "<*>"; + + internal CommandResult TakeHit(Coordinates sector, int hitStrength) + { + _output.WriteLine($"{hitStrength} unit hit on Enterprise from sector {sector}"); + ShieldControl.AbsorbHit(hitStrength); + + if (ShieldControl.ShieldEnergy <= 0) + { + _output.WriteLine(Strings.Destroyed); + return CommandResult.GameOver; + } + + _output.WriteLine($" "); + + if (hitStrength >= 20) + { + TakeDamage(hitStrength); + } + + return CommandResult.Ok; + } + + private void TakeDamage(double hitStrength) + { + var hitShieldRatio = hitStrength / ShieldControl.ShieldEnergy; + if (_random.GetDouble() > 0.6 || hitShieldRatio <= 0.02) + { + return; + } + + _systems[_random.Get1To8Inclusive() - 1].TakeDamage(hitShieldRatio + 0.5 * _random.GetDouble()); + } } } diff --git a/84 Super Star Trek/csharp/Objects/Klingon.cs b/84 Super Star Trek/csharp/Objects/Klingon.cs index fdf47031..0bbaf984 100644 --- a/84 Super Star Trek/csharp/Objects/Klingon.cs +++ b/84 Super Star Trek/csharp/Objects/Klingon.cs @@ -1,14 +1,30 @@ +using SuperStarTrek.Commands; +using SuperStarTrek.Space; + namespace SuperStarTrek.Objects { internal class Klingon { private double _energy; + private Coordinates _sector; + private readonly Random _random; - public Klingon() + public Klingon(Coordinates sector, Random random) { - _energy = new Random().GetDouble(100, 300); + _sector = sector; + _random = random; + _energy = _random.GetDouble(100, 300); } public override string ToString() => "+K+"; + + public CommandResult FireOn(Enterprise enterprise) + { + var attackStrength = _random.GetDouble(); + var hitStrength = (int)(_energy * (2 + attackStrength) / _sector.GetDistanceTo(enterprise.Sector)); + _energy /= 3 + attackStrength; + + return enterprise.TakeHit(_sector, hitStrength); + } } } diff --git a/84 Super Star Trek/csharp/Objects/Starbase.cs b/84 Super Star Trek/csharp/Objects/Starbase.cs index e11ca9f5..b96ffab1 100644 --- a/84 Super Star Trek/csharp/Objects/Starbase.cs +++ b/84 Super Star Trek/csharp/Objects/Starbase.cs @@ -8,10 +8,11 @@ namespace SuperStarTrek.Objects private readonly Output _output; private readonly double _repairDelay; - public Starbase(Random random, Input input) + public Starbase(Random random, Input input, Output output) { _repairDelay = random.GetDouble() * 0.5; _input = input; + _output = output; } public override string ToString() => ">!<"; @@ -34,5 +35,7 @@ namespace SuperStarTrek.Objects repairTime = 0; return false; } + + internal void ProtectEnterprise() => _output.WriteLine(Strings.Protected); } } diff --git a/84 Super Star Trek/csharp/Resources/CourtMartial.txt b/84 Super Star Trek/csharp/Resources/CourtMartial.txt new file mode 100644 index 00000000..7d05a5b8 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/CourtMartial.txt @@ -0,0 +1,3 @@ + +Starfleet Command reviewing your record to consider +court martial! \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/Protected.txt b/84 Super Star Trek/csharp/Resources/Protected.txt new file mode 100644 index 00000000..27c4a5f8 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/Protected.txt @@ -0,0 +1 @@ +Starbase shields protect the Enterprise \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/RelievedOfCommand.txt b/84 Super Star Trek/csharp/Resources/RelievedOfCommand.txt new file mode 100644 index 00000000..8086e3ca --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/RelievedOfCommand.txt @@ -0,0 +1,3 @@ + +That does it, Captain!! You are hereby relieved of command +and sentenced to 99 stardates at hard labor on Cygnus 12!! \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Resources/Strings.cs b/84 Super Star Trek/csharp/Resources/Strings.cs index 210d22ba..c76fe691 100644 --- a/84 Super Star Trek/csharp/Resources/Strings.cs +++ b/84 Super Star Trek/csharp/Resources/Strings.cs @@ -8,13 +8,16 @@ namespace SuperStarTrek.Resources { public static string CombatArea => GetResource(); public static string Congratulations => GetResource(); + public static string CourtMartial => GetResource(); public static string Destroyed => GetResource(); public static string EndOfMission => GetResource(); public static string Enterprise => GetResource(); public static string Instructions => GetResource(); public static string LowShields => GetResource(); public static string Orders => GetResource(); + public static string Protected => GetResource(); public static string RegionNames => GetResource(); + public static string RelievedOfCommand => GetResource(); public static string RepairEstimate => GetResource(); public static string RepairPrompt => GetResource(); public static string ReplayPrompt => GetResource(); diff --git a/84 Super Star Trek/csharp/Space/Coordinate.cs b/84 Super Star Trek/csharp/Space/Coordinate.cs index aa5b5285..b103a528 100644 --- a/84 Super Star Trek/csharp/Space/Coordinate.cs +++ b/84 Super Star Trek/csharp/Space/Coordinate.cs @@ -24,6 +24,34 @@ namespace SuperStarTrek.Space throw new ArgumentOutOfRangeException(argumentName, value, "Must be 0 to 7 inclusive"); } + private static bool IsValid(int value) => value >= 0 && value <= 7; + public override string ToString() => $"{X+1} , {Y+1}"; + + internal void Deconstruct(out int x, out int y) + { + x = X; + y = Y; + } + + internal static bool TryCreate(float x, float y, out Coordinates coordinates) + { + var roundedX = Round(x); + var roundedY = Round(y); + + if (IsValid(roundedX) && IsValid(roundedY)) + { + coordinates = new Coordinates(roundedX, roundedY); + return true; + } + + coordinates = default; + return false; + + int Round(float value) => (int)Math.Round(value, MidpointRounding.AwayFromZero); + } + + internal float GetDistanceTo(Coordinates destination) => + (float)Math.Sqrt(Math.Pow(X - destination.X, 2) + Math.Pow(Y - destination.Y, 2)); } } diff --git a/84 Super Star Trek/csharp/Space/Course.cs b/84 Super Star Trek/csharp/Space/Course.cs index dd9ecfba..99c48c1a 100644 --- a/84 Super Star Trek/csharp/Space/Course.cs +++ b/84 Super Star Trek/csharp/Space/Course.cs @@ -1,4 +1,5 @@ using System; +using System.Collections.Generic; namespace SuperStarTrek.Space { @@ -24,7 +25,7 @@ namespace SuperStarTrek.Space (0, 1) }; - public Course(double direction) + public Course(float direction) { if (direction < 1 || direction > 9) { @@ -44,7 +45,25 @@ namespace SuperStarTrek.Space DeltaY = baseCardinal.DeltaY + (nextCardinal.DeltaY - baseCardinal.DeltaY) * fractionalDirection; } - public double DeltaX { get; } - public double DeltaY { get; } + public float DeltaX { get; } + public float DeltaY { get; } + + public IEnumerable GetSectorsFrom(Coordinates start) + { + (double x, double y) = start; + + while(true) + { + x += DeltaX; + y += DeltaY; + + if (!Coordinates.TryCreate(x, y, out var coordinates)) + { + yield break; + } + + yield return coordinates; + } + } } } diff --git a/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs index e483604f..d89d60e0 100644 --- a/84 Super Star Trek/csharp/Space/Quadrant.cs +++ b/84 Super Star Trek/csharp/Space/Quadrant.cs @@ -1,7 +1,9 @@ using System; using System.Collections.Generic; using System.Linq; +using SuperStarTrek.Commands; using SuperStarTrek.Objects; +using SuperStarTrek.Resources; namespace SuperStarTrek.Space { @@ -10,43 +12,47 @@ namespace SuperStarTrek.Space private readonly QuadrantInfo _info; private readonly Random _random; private readonly Dictionary _sectors; - private readonly Coordinates _enterpriseSector; + private readonly Enterprise _enterprise; private readonly Coordinates _starbaseSector; + private readonly Galaxy _galaxy; - public Quadrant(QuadrantInfo info, Enterprise enterprise) + public Quadrant(QuadrantInfo info, Enterprise enterprise, Random random, Galaxy galaxy) { _info = info; - _random = new Random(); + _random = random; + _galaxy = galaxy; - _enterpriseSector = enterprise.Sector; - _sectors = new Dictionary { [enterprise.Sector] = enterprise }; - PositionObject(() => new Klingon(), _info.KlingonCount); + _sectors = new() { [enterprise.Sector] = _enterprise = enterprise }; + PositionObject(sector => new Klingon(sector, _random), _info.KlingonCount); if (_info.HasStarbase) { - _starbaseSector = PositionObject(() => new Starbase(_random, new Input(new Output()))); + _starbaseSector = PositionObject(_ => new Starbase(_random, new Input(new Output()), new Output())); } - PositionObject(() => new Star(), _info.StarCount); + PositionObject(_ => new Star(), _info.StarCount); } + public object this[Coordinates coordinates] => _sectors.GetValueOrDefault(coordinates); public Coordinates Coordinates => _info.Coordinates; public bool HasKlingons => _info.KlingonCount > 0; public bool HasStarbase => _info.HasStarbase; public Starbase Starbase => HasStarbase ? (Starbase)_sectors[_starbaseSector] : null; public bool EnterpriseIsNextToStarbase => _info.HasStarbase && - Math.Abs(_enterpriseSector.X - _starbaseSector.X) <= 1 && - Math.Abs(_enterpriseSector.Y - _starbaseSector.Y) <= 1; + Math.Abs(_enterprise.Sector.X - _starbaseSector.X) <= 1 && + Math.Abs(_enterprise.Sector.Y - _starbaseSector.Y) <= 1; + + private IEnumerable Klingons => _sectors.Values.OfType(); public override string ToString() => _info.Name; - private Coordinates PositionObject(Func objectFactory) + private Coordinates PositionObject(Func objectFactory) { var sector = GetRandomEmptySector(); - _sectors[sector] = objectFactory.Invoke(); + _sectors[sector] = objectFactory.Invoke(sector); return sector; } - private void PositionObject(Func objectFactory, int count) + private void PositionObject(Func objectFactory, int count) { for (int i = 0; i < count; i++) { @@ -54,6 +60,54 @@ namespace SuperStarTrek.Space } } + internal bool TorpedoCollisionAt(Coordinates coordinates, out string message, out bool gameOver) + { + gameOver = false; + message = default; + + switch (_sectors.GetValueOrDefault(coordinates)) + { + case Klingon _: + _sectors.Remove(coordinates); + _info.RemoveKlingon(); + message = "*** Klingon destroyed ***"; + gameOver = _galaxy.KlingonCount == 0; + return true; + + case Star _: + message = $"Star at {coordinates} absorbed torpedo energy."; + return true; + + case Starbase _: + _sectors.Remove(coordinates); + _info.RemoveStarbase(); + message = "*** Starbase destroyed ***" + + (_galaxy.StarbaseCount > 0 ? Strings.CourtMartial : Strings.RelievedOfCommand); + gameOver = _galaxy.StarbaseCount == 0; + return true; + + default: + return false; + } + } + + internal CommandResult KlingonsFireOnEnterprise() + { + if (EnterpriseIsNextToStarbase && Klingons.Any()) + { + Starbase.ProtectEnterprise(); + return CommandResult.Ok; + } + + foreach (var klingon in Klingons) + { + var result = klingon.FireOn(_enterprise); + if (result.IsGameOver) { return result; } + } + + return CommandResult.Ok; + } + private Coordinates GetRandomEmptySector() { while (true) diff --git a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs index 20f21ee2..284c8c84 100644 --- a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs +++ b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs @@ -1,3 +1,5 @@ +using SuperStarTrek.Objects; + namespace SuperStarTrek.Space { internal class QuadrantInfo @@ -39,12 +41,25 @@ namespace SuperStarTrek.Space internal void AddStarbase() => HasStarbase = true; - public string Scan() + internal Quadrant BuildQuadrant(Enterprise enterprise, Random random, Galaxy galaxy) => + new(this, enterprise, random, galaxy); + + internal string Scan() { _isKnown = true; return ToString(); } public override string ToString() => _isKnown ? $"{KlingonCount}{(HasStarbase ? 1 : 0)}{StarCount}" : "***"; + + internal void RemoveKlingon() + { + if (KlingonCount > 0) + { + KlingonCount -= 1; + } + } + + internal void RemoveStarbase() => HasStarbase = false; } } diff --git a/84 Super Star Trek/csharp/Systems/DamageControl.cs b/84 Super Star Trek/csharp/Systems/DamageControl.cs index b4587add..25f5ad78 100644 --- a/84 Super Star Trek/csharp/Systems/DamageControl.cs +++ b/84 Super Star Trek/csharp/Systems/DamageControl.cs @@ -10,13 +10,13 @@ namespace SuperStarTrek.Systems private readonly Output _output; public DamageControl(Enterprise enterprise, Output output) - : base("Damage Control", Command.DAM) + : base("Damage Control", Command.DAM, output) { _enterprise = enterprise; _output = output; } - public override CommandResult ExecuteCommand(Quadrant quadrant) + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) { if (IsDamaged) { diff --git a/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs b/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs index 233af4a6..84ed7a87 100644 --- a/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs +++ b/84 Super Star Trek/csharp/Systems/LongRangeSensors.cs @@ -15,27 +15,22 @@ namespace SuperStarTrek.Systems private readonly Output _output; public LongRangeSensors(Galaxy galaxy, Output output) - : base("Long Range Sensors", Command.LRS) + : base("Long Range Sensors", Command.LRS, output) { _galaxy = galaxy; _output = output; } - public override CommandResult ExecuteCommand(Quadrant quadrant) + protected override bool CanExecuteCommand() => IsOperational("{name} are inoperable"); + + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) { - if (Condition < 0) + _output.WriteLine($"Long range scan for quadrant {quadrant.Coordinates}"); + _output.WriteLine("-------------------"); + foreach (var quadrants in _galaxy.GetNeighborhood(quadrant)) { - _output.WriteLine("Long Range Sensors are inoperable"); - } - else - { - _output.WriteLine($"Long range scan for quadrant {quadrant.Coordinates}"); + _output.WriteLine(": " + string.Join(" : ", quadrants.Select(q => q?.Scan() ?? "***")) + " :"); _output.WriteLine("-------------------"); - foreach (var quadrants in _galaxy.GetNeighborhood(quadrant)) - { - _output.WriteLine(": " + string.Join(" : ", quadrants.Select(q => q?.Scan() ?? "***")) + " :"); - _output.WriteLine("-------------------"); - } } return CommandResult.Ok; diff --git a/84 Super Star Trek/csharp/Systems/PhotonTubes.cs b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs new file mode 100644 index 00000000..034199c9 --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs @@ -0,0 +1,63 @@ +using SuperStarTrek.Commands; +using SuperStarTrek.Objects; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems +{ + internal class PhotonTubes : Subsystem + { + private readonly int _tubeCount; + private readonly Enterprise _enterprise; + private readonly Output _output; + private readonly Input _input; + + public PhotonTubes(int tubeCount, Enterprise enterprise, Output output, Input input) + : base("Photon Tubes", Command.TOR, output) + { + TorpedoCount = _tubeCount = tubeCount; + _enterprise = enterprise; + _output = output; + _input = input; + } + + public int TorpedoCount { get; private set; } + + protected override bool CanExecuteCommand() => HasTorpedoes() && IsOperational("{name} are not operational"); + + private bool HasTorpedoes() + { + if (TorpedoCount > 0) { return true; } + + _output.WriteLine("All photon torpedoes expended"); + return false; + } + + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) + { + if (!_input.TryGetNumber("Photon torpedo course", 1, 9, out var direction)) + { + _output.WriteLine("Ensign Chekov reports, 'Incorrect course data, sir!'"); + return CommandResult.Ok; + } + + var isHit = false; + _output.WriteLine("Torpedo track:"); + foreach (var sector in new Course(direction).GetSectorsFrom(_enterprise.Sector)) + { + _output.WriteLine($" {sector}"); + + if (quadrant.TorpedoCollisionAt(sector, out var message, out var gameOver)) + { + _output.WriteLine(message); + isHit = true; + if (gameOver) { return CommandResult.GameOver; } + break; + } + } + + if (!isHit) { _output.WriteLine("Torpedo missed!"); } + + return quadrant.KlingonsFireOnEnterprise(); + } + } +} diff --git a/84 Super Star Trek/csharp/Systems/ShieldControl.cs b/84 Super Star Trek/csharp/Systems/ShieldControl.cs index 9c4a3c16..48320588 100644 --- a/84 Super Star Trek/csharp/Systems/ShieldControl.cs +++ b/84 Super Star Trek/csharp/Systems/ShieldControl.cs @@ -11,7 +11,7 @@ namespace SuperStarTrek.Systems private readonly Input _input; public ShieldControl(Enterprise enterprise, Output output, Input input) - : base("Shield Control", Command.SHE) + : base("Shield Control", Command.SHE, output) { _enterprise = enterprise; _output = output; @@ -20,21 +20,9 @@ namespace SuperStarTrek.Systems public double ShieldEnergy { get; private set; } - public override CommandResult ExecuteCommand(Quadrant quadrant) - { - if (Condition < 0) - { - _output.WriteLine("Shield Control inoperable"); - } - else - { - UpdateShields(); - } + protected override bool CanExecuteCommand() => IsOperational("{name} inoperable"); - return CommandResult.Ok; - } - - private void UpdateShields() + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) { _output.WriteLine($"Energy available = {_enterprise.TotalEnergy}"); var requested = _input.GetNumber($"Number of units to shields"); @@ -47,6 +35,8 @@ namespace SuperStarTrek.Systems { _output.WriteLine(""); } + + return CommandResult.Ok; } private bool Validate(double requested) @@ -59,5 +49,7 @@ namespace SuperStarTrek.Systems return requested >= 0 && requested != ShieldEnergy; } + + internal void AbsorbHit(int hitStrength) => ShieldEnergy -= hitStrength; } } diff --git a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs index 953ec66e..e01c829e 100644 --- a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs +++ b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs @@ -17,7 +17,7 @@ namespace SuperStarTrek.Systems private readonly Output _output; public ShortRangeSensors(Enterprise enterprise, Galaxy galaxy, Game game, Output output) - : base("Short Range Sensors", Command.SRS) + : base("Short Range Sensors", Command.SRS, output) { _enterprise = enterprise; _galaxy = galaxy; @@ -25,7 +25,7 @@ namespace SuperStarTrek.Systems _output = output; } - public override CommandResult ExecuteCommand(Quadrant quadrant) + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) { if (_enterprise.IsDocked) { diff --git a/84 Super Star Trek/csharp/Systems/Subsystem.cs b/84 Super Star Trek/csharp/Systems/Subsystem.cs index 53398b41..88924a8c 100644 --- a/84 Super Star Trek/csharp/Systems/Subsystem.cs +++ b/84 Super Star Trek/csharp/Systems/Subsystem.cs @@ -1,3 +1,4 @@ +using System; using SuperStarTrek.Commands; using SuperStarTrek.Space; @@ -5,11 +6,14 @@ namespace SuperStarTrek.Systems { internal abstract class Subsystem { - protected Subsystem(string name, Command command) + private readonly Output _output; + + protected Subsystem(string name, Command command, Output output) { Name = name; Command = command; Condition = 0; + _output = output; } public string Name { get; } @@ -17,10 +21,33 @@ namespace SuperStarTrek.Systems public bool IsDamaged => Condition < 0; public Command Command { get; } - public abstract CommandResult ExecuteCommand(Quadrant quadrant); - public void Repair() + protected virtual bool CanExecuteCommand() => true; + + protected bool IsOperational(string notOperationalMessage) { - if (Condition < 0) { Condition = 0; } + if (IsDamaged) + { + _output.WriteLine(notOperationalMessage.Replace("{name}", Name)); + return false; + } + + return true; + } + + public CommandResult ExecuteCommand(Quadrant quadrant) + => CanExecuteCommand() ? ExecuteCommandCore(quadrant) : CommandResult.Ok; + + protected abstract CommandResult ExecuteCommandCore(Quadrant quadrant); + + public virtual void Repair() + { + if (IsDamaged) { Condition = 0; } + } + + internal void TakeDamage(double damage) + { + Condition -= damage; + _output.WriteLine($"Damage Control reports, '{Name} damaged by the hit.'"); } } }