diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index e32f15c8..de3c2c4c 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -83,6 +83,7 @@ namespace SuperStarTrek _enterprise .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) .Add(new LongRangeSensors(_galaxy, _output)) + .Add(new PhaserControl(_enterprise, _output, _input, random)) .Add(new PhotonTubes(10, _enterprise, _output, _input)) .Add(new ShieldControl(_enterprise, _output, _input)) .Add(new DamageControl(_enterprise, _output)) diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index ed11bb1e..d87a3aec 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -32,6 +32,7 @@ namespace SuperStarTrek.Objects public Coordinates Quadrant => _quadrant.Coordinates; public Coordinates Sector { get; } public string Condition => GetCondition(); + public LibraryComputer Computer => (LibraryComputer)_commandExecutors[Command.COM]; public ShieldControl ShieldControl => (ShieldControl)_commandExecutors[Command.SHE]; public float Energy => TotalEnergy - ShieldControl.ShieldEnergy; public float TotalEnergy { get; private set; } diff --git a/84 Super Star Trek/csharp/Objects/Klingon.cs b/84 Super Star Trek/csharp/Objects/Klingon.cs index f722fe06..d16c6792 100644 --- a/84 Super Star Trek/csharp/Objects/Klingon.cs +++ b/84 Super Star Trek/csharp/Objects/Klingon.cs @@ -5,16 +5,16 @@ namespace SuperStarTrek.Objects { internal class Klingon { - private float _energy; private readonly Random _random; public Klingon(Coordinates sector, Random random) { Sector = sector; _random = random; - _energy = _random.GetFloat(100, 300); + Energy = _random.GetFloat(100, 300); } + public float Energy { get; private set; } public Coordinates Sector { get; private set; } public override string ToString() => "+K+"; @@ -22,11 +22,19 @@ namespace SuperStarTrek.Objects public CommandResult FireOn(Enterprise enterprise) { var attackStrength = _random.GetFloat(); - var (_, distanceToEnterprise) = Sector.GetDirectionAndDistanceTo(enterprise.Sector); - var hitStrength = (int)(_energy * (2 + attackStrength) / distanceToEnterprise); - _energy /= 3 + attackStrength; + var distanceToEnterprise = Sector.GetDistanceTo(enterprise.Sector); + var hitStrength = (int)(Energy * (2 + attackStrength) / distanceToEnterprise); + Energy /= 3 + attackStrength; return enterprise.TakeHit(Sector, hitStrength); } + + internal bool TakeHit(int hitStrength) + { + if (hitStrength < 0.15 * Energy) { return false; } + + Energy -= hitStrength; + return true; + } } } diff --git a/84 Super Star Trek/csharp/Space/Coordinate.cs b/84 Super Star Trek/csharp/Space/Coordinate.cs index b8660d52..759ca45e 100644 --- a/84 Super Star Trek/csharp/Space/Coordinate.cs +++ b/84 Super Star Trek/csharp/Space/Coordinate.cs @@ -57,5 +57,11 @@ namespace SuperStarTrek.Space internal (float Direction, float Distance) GetDirectionAndDistanceTo(Coordinates destination) => DirectionAndDistance.From(this).To(destination); + + internal float GetDistanceTo(Coordinates destination) + { + var (_, distance) = GetDirectionAndDistanceTo(destination); + return distance; + } } } diff --git a/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs index efcaadb2..8d9d0556 100644 --- a/84 Super Star Trek/csharp/Space/Quadrant.cs +++ b/84 Super Star Trek/csharp/Space/Quadrant.cs @@ -72,10 +72,8 @@ namespace SuperStarTrek.Space switch (_sectors.GetValueOrDefault(coordinates)) { - case Klingon _: - _sectors.Remove(coordinates); - _info.RemoveKlingon(); - message = "*** Klingon destroyed ***"; + case Klingon klingon: + message = Remove(klingon); gameOver = _galaxy.KlingonCount == 0; return true; @@ -96,6 +94,13 @@ namespace SuperStarTrek.Space } } + internal string Remove(Klingon klingon) + { + _sectors.Remove(klingon.Sector); + _info.RemoveKlingon(); + return "*** Klingon destroyed ***"; + } + internal CommandResult KlingonsFireOnEnterprise() { if (EnterpriseIsNextToStarbase && Klingons.Any()) diff --git a/84 Super Star Trek/csharp/Systems/PhaserControl.cs b/84 Super Star Trek/csharp/Systems/PhaserControl.cs new file mode 100644 index 00000000..48da4ace --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/PhaserControl.cs @@ -0,0 +1,95 @@ +using System.Linq; +using SuperStarTrek.Commands; +using SuperStarTrek.Objects; +using SuperStarTrek.Resources; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems +{ + internal class PhaserControl : Subsystem + { + private readonly Enterprise _enterprise; + private readonly Output _output; + private readonly Input _input; + private readonly Random _random; + + public PhaserControl(Enterprise enterprise, Output output, Input input, Random random) + : base("Phaser Control", Command.PHA, output) + { + _enterprise = enterprise; + _output = output; + _input = input; + _random = random; + } + + protected override bool CanExecuteCommand() => IsOperational("Phasers inoperative"); + + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) + { + if (!quadrant.HasKlingons) + { + _output.WriteLine(Strings.NoEnemyShips); + return CommandResult.Ok; + } + + if (_enterprise.Computer.IsDamaged) + { + _output.WriteLine("Computer failure hampers accuracy"); + } + + _output.Write($"Phasers locked on target; "); + + var phaserStrength = GetPhaserStrength(); + if (phaserStrength < 0) { return CommandResult.Ok; } + + var perEnemyStrength = GetPerTargetPhaserStrength(phaserStrength, quadrant.KlingonCount); + + foreach (var klingon in quadrant.Klingons.ToList()) + { + ResolveHitOn(klingon, perEnemyStrength, quadrant); + } + + return quadrant.KlingonsFireOnEnterprise(); + } + + private float GetPhaserStrength() + { + while (true) + { + _output.WriteLine($"Energy available = {_enterprise.Energy} units"); + var phaserStrength = _input.GetNumber("Number of units to fire"); + + if (phaserStrength <= _enterprise.Energy) { return phaserStrength; } + } + } + + private float GetPerTargetPhaserStrength(float phaserStrength, int targetCount) + { + if (_enterprise.Computer.IsDamaged) + { + phaserStrength *= _random.GetFloat(); + } + + return phaserStrength / targetCount; + } + + private void ResolveHitOn(Klingon klingon, float perEnemyStrength, Quadrant quadrant) + { + var distance = _enterprise.Sector.GetDistanceTo(klingon.Sector); + var hitStrength = (int)(perEnemyStrength / distance * (2 + _random.GetFloat())); + + if (klingon.TakeHit(hitStrength)) + { + _output.WriteLine($"{hitStrength} unit hit on Klingon at sector {klingon.Sector}"); + _output.WriteLine( + klingon.Energy <= 0 + ? quadrant.Remove(klingon) + : $" (sensors show {klingon.Energy} units remaining)"); + } + else + { + _output.WriteLine($"Sensors show no damage to enemy at {klingon.Sector}"); + } + } + } +}