From 835ee3546481a21904fae9ecccbdcc7d448e1ed8 Mon Sep 17 00:00:00 2001 From: Andrew Cooper Date: Sun, 21 Mar 2021 12:39:19 +1100 Subject: [PATCH] Add Warp Engines --- 84 Super Star Trek/csharp/Game.cs | 27 ++-- 84 Super Star Trek/csharp/Input.cs | 15 ++- .../csharp/Objects/Enterprise.cs | 120 +++++++++++++++--- 84 Super Star Trek/csharp/Objects/Klingon.cs | 4 +- .../csharp/Resources/NowEntering.txt | 2 + .../csharp/Resources/PermissionDenied.txt | 5 + .../csharp/Resources/Strings.cs | 2 + .../Space/{Coordinate.cs => Coordinates.cs} | 2 +- 84 Super Star Trek/csharp/Space/Course.cs | 36 +++++- 84 Super Star Trek/csharp/Space/Galaxy.cs | 6 +- 84 Super Star Trek/csharp/Space/Quadrant.cs | 52 ++++++-- .../csharp/Space/QuadrantInfo.cs | 6 +- .../DirectionDistanceCalculator.cs | 3 +- .../StarbaseDataCalculator.cs | 2 +- .../TorpedoDataCalculator.cs | 2 +- .../csharp/Systems/PhaserControl.cs | 2 +- .../csharp/Systems/PhotonTubes.cs | 5 +- .../csharp/Systems/ShortRangeSensors.cs | 4 +- .../csharp/Systems/Subsystem.cs | 21 ++- .../csharp/Systems/WarpEngines.cs | 75 +++++++++++ 20 files changed, 330 insertions(+), 61 deletions(-) create mode 100644 84 Super Star Trek/csharp/Resources/NowEntering.txt create mode 100644 84 Super Star Trek/csharp/Resources/PermissionDenied.txt rename 84 Super Star Trek/csharp/Space/{Coordinate.cs => Coordinates.cs} (95%) create mode 100644 84 Super Star Trek/csharp/Systems/WarpEngines.cs diff --git a/84 Super Star Trek/csharp/Game.cs b/84 Super Star Trek/csharp/Game.cs index de3c2c4c..f2e1c819 100644 --- a/84 Super Star Trek/csharp/Game.cs +++ b/84 Super Star Trek/csharp/Game.cs @@ -12,6 +12,7 @@ namespace SuperStarTrek { private readonly Output _output; private readonly Input _input; + private readonly Random _random; private int _initialStardate; private int _finalStarDate; @@ -25,6 +26,7 @@ namespace SuperStarTrek { _output = new Output(); _input = new Input(_output); + _random = new Random(); } public float Stardate => _currentStardate; @@ -46,15 +48,19 @@ namespace SuperStarTrek { Initialise(); var gameOver = false; + var newQuadrantText = Strings.StartText; while (!gameOver) { + _enterprise.Quadrant.Display(Strings.NowEntering); + var command = _input.GetCommand(); var result = _enterprise.Execute(command); gameOver = result.IsGameOver || CheckIfStranded(); _currentStardate += result.TimeElapsed; + gameOver |= _currentStardate > _finalStarDate; } if (_galaxy.KlingonCount > 0) @@ -69,21 +75,20 @@ namespace SuperStarTrek private void Initialise() { - var random = new Random(); + _currentStardate = _initialStardate = _random.GetInt(20, 40) * 100; + _finalStarDate = _initialStardate + _random.GetInt(25, 35); - _currentStardate = _initialStardate = random.GetInt(20, 40) * 100; - _finalStarDate = _initialStardate + random.GetInt(25, 35); + _currentQuadrant = _random.GetCoordinate(); - _currentQuadrant = random.GetCoordinate(); - - _galaxy = new Galaxy(); + _galaxy = new Galaxy(_random); _initialKlingonCount = _galaxy.KlingonCount; - _enterprise = new Enterprise(3000, random.GetCoordinate(), _output, random); + _enterprise = new Enterprise(3000, _random.GetCoordinate(), _output, _random, _input); _enterprise + .Add(new WarpEngines(_enterprise, _output, _input)) .Add(new ShortRangeSensors(_enterprise, _galaxy, this, _output)) .Add(new LongRangeSensors(_galaxy, _output)) - .Add(new PhaserControl(_enterprise, _output, _input, random)) + .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)) @@ -109,10 +114,12 @@ namespace SuperStarTrek _input.WaitForAnyKeyButEnter("when ready to accept command"); - var quadrant = _galaxy[_currentQuadrant].BuildQuadrant(_enterprise, random, _galaxy, _input, _output); - _enterprise.Enter(quadrant, Strings.StartText); + _enterprise.StartIn(BuildCurrentQuadrant()); } + private Quadrant BuildCurrentQuadrant() => + new Quadrant(_galaxy[_currentQuadrant], _enterprise, _random, _galaxy, _input, _output); + public bool Replay() => _galaxy.StarbaseCount > 0 && _input.GetString(Strings.ReplayPrompt, "Aye"); private bool CheckIfStranded() diff --git a/84 Super Star Trek/csharp/Input.cs b/84 Super Star Trek/csharp/Input.cs index af17f3c4..3011738b 100644 --- a/84 Super Star Trek/csharp/Input.cs +++ b/84 Super Star Trek/csharp/Input.cs @@ -1,7 +1,7 @@ using System; using System.Linq; using SuperStarTrek.Commands; - +using SuperStarTrek.Space; using static System.StringComparison; namespace SuperStarTrek @@ -82,6 +82,19 @@ namespace SuperStarTrek } } + public bool TryGetCourse(string prompt, string officer, out Course course) + { + if (!TryGetNumber(prompt, 1, 9, out var direction)) + { + _output.WriteLine($"{officer} reports, 'Incorrect course data, sir!'"); + course = default; + return false; + } + + course = new Course(direction); + return true; + } + public bool GetYesNo(string prompt, YesNoMode mode) { _output.Prompt($"{prompt} (Y/N)"); diff --git a/84 Super Star Trek/csharp/Objects/Enterprise.cs b/84 Super Star Trek/csharp/Objects/Enterprise.cs index d87a3aec..004ce893 100644 --- a/84 Super Star Trek/csharp/Objects/Enterprise.cs +++ b/84 Super Star Trek/csharp/Objects/Enterprise.cs @@ -16,21 +16,25 @@ namespace SuperStarTrek.Objects private readonly List _systems; private readonly Dictionary _commandExecutors; private readonly Random _random; + private readonly Input _input; private Quadrant _quadrant; - public Enterprise(int maxEnergy, Coordinates sector, Output output, Random random) + public Enterprise(int maxEnergy, Coordinates sector, Output output, Random random, Input input) { - Sector = sector; + SectorCoordinates = sector; TotalEnergy = _maxEnergy = maxEnergy; _systems = new List(); _commandExecutors = new Dictionary(); _output = output; _random = random; + _input = input; } - public Coordinates Quadrant => _quadrant.Coordinates; - public Coordinates Sector { get; } + public Quadrant Quadrant => _quadrant; + public Coordinates QuadrantCoordinates => _quadrant.Coordinates; + public Coordinates SectorCoordinates { get; private set; } + public string Condition => GetCondition(); public LibraryComputer Computer => (LibraryComputer)_commandExecutors[Command.COM]; public ShieldControl ShieldControl => (ShieldControl)_commandExecutors[Command.SHE]; @@ -50,19 +54,10 @@ namespace SuperStarTrek.Objects return this; } - public void Enter(Quadrant quadrant, string entryTextFormat) + public void StartIn(Quadrant quadrant) { _quadrant = quadrant; - - _output.Write(entryTextFormat, quadrant); - - if (quadrant.HasKlingons) - { - _output.Write(Strings.CombatArea); - if (ShieldControl.ShieldEnergy <= 200) { _output.Write(Strings.LowShields); } - } - - Execute(Command.SRS); + quadrant.Display(Strings.StartText); } private string GetCondition() => @@ -121,7 +116,100 @@ namespace SuperStarTrek.Objects return; } - _systems[_random.Get1To8Inclusive() - 1].TakeDamage(hitShieldRatio + 0.5f * _random.GetFloat()); + var system = _systems[_random.Get1To8Inclusive() - 1]; + system.TakeDamage(hitShieldRatio + 0.5f * _random.GetFloat()); + _output.WriteLine($"Damage Control reports, '{system.Name} damaged by the hit.'"); } + + internal void RepairSystems(float repairWorkDone) + { + var repairedSystems = new List(); + + foreach (var system in _systems.Where(s => s.IsDamaged)) + { + if (system.Repair(repairWorkDone)) + { + repairedSystems.Add(system.Name); + } + } + + if (repairedSystems.Any()) + { + _output.WriteLine("Damage Control report:"); + foreach (var systemName in repairedSystems) + { + _output.WriteLine($" {systemName} repair completed."); + } + } + } + + internal void VaryConditionOfRandomSystem() + { + if (_random.GetFloat() > 0.2f) { return; } + + var system = _systems[_random.Get1To8Inclusive() - 1]; + _output.Write($"Damage Control report: {system.Name} "); + if (_random.GetFloat() >= 0.6) + { + system.Repair(_random.GetFloat() * 3 + 1); + _output.WriteLine("state of repair improved"); + } + else + { + system.TakeDamage(_random.GetFloat() * 5 + 1); + _output.WriteLine("damaged"); + } + } + + internal float Move(Course course, float warpFactor, int distance) + { + var (quadrant, sector) = MoveWithinQuadrant(course, distance) ?? MoveBeyondQuadrant(course, distance); + + if (quadrant != _quadrant.Coordinates) + { + _quadrant = new Quadrant(_quadrant.Galaxy[quadrant], this, _random, _quadrant.Galaxy, _input, _output); + } + SectorCoordinates = sector; + + return GetTimeElapsed(quadrant, warpFactor); + } + + private (Coordinates, Coordinates)? MoveWithinQuadrant(Course course, int distance) + { + var currentSector = SectorCoordinates; + foreach (var (sector, index) in course.GetSectorsFrom(SectorCoordinates).Select((s, i) => (s, i))) + { + if (distance == 0) { break; } + + if (_quadrant.HasObjectAt(sector)) + { + _output.WriteLine($"Warp engines shut down at sector {currentSector} dues to bad navigation"); + distance = 0; + break; + } + + currentSector = sector; + distance -= 1; + } + + return distance == 0 ? (_quadrant.Coordinates, currentSector) : null; + } + + private (Coordinates, Coordinates) MoveBeyondQuadrant(Course course, int distance) + { + var (complete, quadrant, sector) = course.GetDestination(QuadrantCoordinates, SectorCoordinates, distance); + + if (!complete) + { + _output.Write(Strings.PermissionDenied, sector, quadrant); + } + + return (quadrant, sector); + } + + private float GetTimeElapsed(Coordinates finalQuadrant, float warpFactor) => + finalQuadrant == _quadrant.Coordinates + ? Math.Min(1, (float)Math.Round(warpFactor, 1, MidpointRounding.ToZero)) + : 1; } } diff --git a/84 Super Star Trek/csharp/Objects/Klingon.cs b/84 Super Star Trek/csharp/Objects/Klingon.cs index d16c6792..4e277b07 100644 --- a/84 Super Star Trek/csharp/Objects/Klingon.cs +++ b/84 Super Star Trek/csharp/Objects/Klingon.cs @@ -22,7 +22,7 @@ namespace SuperStarTrek.Objects public CommandResult FireOn(Enterprise enterprise) { var attackStrength = _random.GetFloat(); - var distanceToEnterprise = Sector.GetDistanceTo(enterprise.Sector); + var distanceToEnterprise = Sector.GetDistanceTo(enterprise.SectorCoordinates); var hitStrength = (int)(Energy * (2 + attackStrength) / distanceToEnterprise); Energy /= 3 + attackStrength; @@ -36,5 +36,7 @@ namespace SuperStarTrek.Objects Energy -= hitStrength; return true; } + + internal void MoveTo(Coordinates newSector) => Sector = newSector; } } diff --git a/84 Super Star Trek/csharp/Resources/NowEntering.txt b/84 Super Star Trek/csharp/Resources/NowEntering.txt new file mode 100644 index 00000000..915b526f --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/NowEntering.txt @@ -0,0 +1,2 @@ +Now entering {0} quadrant . . . + diff --git a/84 Super Star Trek/csharp/Resources/PermissionDenied.txt b/84 Super Star Trek/csharp/Resources/PermissionDenied.txt new file mode 100644 index 00000000..c24d9da7 --- /dev/null +++ b/84 Super Star Trek/csharp/Resources/PermissionDenied.txt @@ -0,0 +1,5 @@ +Lt. Uhura report message from Starfleet Command: + 'Permission to attempt crossing of galactic perimeter + is hereby *Denied*. Shut down your engines.' +Chief Engineer Scott reports, 'Warp engines shut down + at sector {0} of quadrant {1}.' diff --git a/84 Super Star Trek/csharp/Resources/Strings.cs b/84 Super Star Trek/csharp/Resources/Strings.cs index 7b315545..ddb768ca 100644 --- a/84 Super Star Trek/csharp/Resources/Strings.cs +++ b/84 Super Star Trek/csharp/Resources/Strings.cs @@ -17,7 +17,9 @@ namespace SuperStarTrek.Resources public static string LowShields => GetResource(); public static string NoEnemyShips => GetResource(); public static string NoStarbase => GetResource(); + public static string NowEntering => GetResource(); public static string Orders => GetResource(); + public static string PermissionDenied => GetResource(); public static string Protected => GetResource(); public static string RegionNames => GetResource(); public static string RelievedOfCommand => GetResource(); diff --git a/84 Super Star Trek/csharp/Space/Coordinate.cs b/84 Super Star Trek/csharp/Space/Coordinates.cs similarity index 95% rename from 84 Super Star Trek/csharp/Space/Coordinate.cs rename to 84 Super Star Trek/csharp/Space/Coordinates.cs index 759ca45e..1619d387 100644 --- a/84 Super Star Trek/csharp/Space/Coordinate.cs +++ b/84 Super Star Trek/csharp/Space/Coordinates.cs @@ -52,7 +52,7 @@ namespace SuperStarTrek.Space coordinates = default; return false; - int Round(float value) => (int)Math.Round(value, MidpointRounding.AwayFromZero); + static int Round(float value) => (int)Math.Round(value, MidpointRounding.AwayFromZero); } internal (float Direction, float Distance) GetDirectionAndDistanceTo(Coordinates destination) => diff --git a/84 Super Star Trek/csharp/Space/Course.cs b/84 Super Star Trek/csharp/Space/Course.cs index 40bf4bb2..a46385c3 100644 --- a/84 Super Star Trek/csharp/Space/Course.cs +++ b/84 Super Star Trek/csharp/Space/Course.cs @@ -25,7 +25,7 @@ namespace SuperStarTrek.Space (0, 1) }; - public Course(float direction) + internal Course(float direction) { if (direction < 1 || direction > 9) { @@ -45,10 +45,10 @@ namespace SuperStarTrek.Space DeltaY = baseCardinal.DeltaY + (nextCardinal.DeltaY - baseCardinal.DeltaY) * fractionalDirection; } - public float DeltaX { get; } - public float DeltaY { get; } + internal float DeltaX { get; } + internal float DeltaY { get; } - public IEnumerable GetSectorsFrom(Coordinates start) + internal IEnumerable GetSectorsFrom(Coordinates start) { (float x, float y) = start; @@ -65,5 +65,33 @@ namespace SuperStarTrek.Space yield return coordinates; } } + + internal (bool, Coordinates, Coordinates) GetDestination(Coordinates quadrant, Coordinates sector, int distance) + { + var (xComplete, quadrantX, sectorX) = GetNewCoordinate(quadrant.X, sector.X, DeltaX * distance); + var (yComplete, quadrantY, sectorY) = GetNewCoordinate(quadrant.Y, sector.Y, DeltaY * distance); + + return (xComplete && yComplete, new Coordinates(quadrantX, quadrantY), new Coordinates(sectorX, sectorY)); + } + + private (bool, int, int) GetNewCoordinate(int quadrant, int sector, float sectorsTravelled) + { + var galacticCoordinate = quadrant * 8 + sector + sectorsTravelled; + var newQuadrant = (int)(galacticCoordinate / 8); + var newSector = (int)(galacticCoordinate - newQuadrant * 8); + + if (newSector == -1) + { + newQuadrant -= 1; + newSector = 7; + } + + return newQuadrant switch + { + < 0 => (false, 0, 0), + > 7 => (false, 7, 7), + _ => (true, newQuadrant, newSector) + }; + } } } diff --git a/84 Super Star Trek/csharp/Space/Galaxy.cs b/84 Super Star Trek/csharp/Space/Galaxy.cs index 38382754..63838567 100644 --- a/84 Super Star Trek/csharp/Space/Galaxy.cs +++ b/84 Super Star Trek/csharp/Space/Galaxy.cs @@ -1,6 +1,7 @@ using System.Collections; using System.Collections.Generic; using System.Linq; +using SuperStarTrek.Objects; using SuperStarTrek.Resources; using static System.StringSplitOptions; @@ -12,6 +13,7 @@ namespace SuperStarTrek.Space private static readonly string[] _regionNames; private static readonly string[] _subRegionIdentifiers; private readonly QuadrantInfo[][] _quadrants; + private readonly Random _random; static Galaxy() { @@ -19,9 +21,9 @@ namespace SuperStarTrek.Space _subRegionIdentifiers = new[] { "I", "II", "III", "IV" }; } - public Galaxy() + public Galaxy(Random random) { - var random = new Random(); + _random = random; _quadrants = Enumerable .Range(0, 8) diff --git a/84 Super Star Trek/csharp/Space/Quadrant.cs b/84 Super Star Trek/csharp/Space/Quadrant.cs index 8d9d0556..50c577e2 100644 --- a/84 Super Star Trek/csharp/Space/Quadrant.cs +++ b/84 Super Star Trek/csharp/Space/Quadrant.cs @@ -13,7 +13,8 @@ namespace SuperStarTrek.Space private readonly Random _random; private readonly Dictionary _sectors; private readonly Enterprise _enterprise; - private readonly Galaxy _galaxy; + private readonly Output _output; + private bool _displayed = false; public Quadrant( QuadrantInfo info, @@ -25,9 +26,11 @@ namespace SuperStarTrek.Space { _info = info; _random = random; - _galaxy = galaxy; + _output = output; + Galaxy = galaxy; - _sectors = new() { [enterprise.Sector] = _enterprise = enterprise }; + info.MarkAsKnown(); + _sectors = new() { [enterprise.SectorCoordinates] = _enterprise = enterprise }; PositionObject(sector => new Klingon(sector, _random), _info.KlingonCount); if (_info.HasStarbase) { @@ -41,10 +44,11 @@ namespace SuperStarTrek.Space public int KlingonCount => _info.KlingonCount; public bool HasStarbase => _info.HasStarbase; public Starbase Starbase { get; } + internal Galaxy Galaxy { get; } public bool EnterpriseIsNextToStarbase => _info.HasStarbase && - Math.Abs(_enterprise.Sector.X - Starbase.Sector.X) <= 1 && - Math.Abs(_enterprise.Sector.Y - Starbase.Sector.Y) <= 1; + Math.Abs(_enterprise.SectorCoordinates.X - Starbase.Sector.X) <= 1 && + Math.Abs(_enterprise.SectorCoordinates.Y - Starbase.Sector.Y) <= 1; internal IEnumerable Klingons => _sectors.Values.OfType(); @@ -65,6 +69,25 @@ namespace SuperStarTrek.Space } } + internal void Display(string textFormat) + { + if (_displayed) { return; } + + _output.Write(textFormat, this); + + if (_info.KlingonCount > 0) + { + _output.Write(Strings.CombatArea); + if (_enterprise.ShieldControl.ShieldEnergy <= 200) { _output.Write(Strings.LowShields); } + } + + _enterprise.Execute(Command.SRS); + + _displayed = true; + } + + internal bool HasObjectAt(Coordinates coordinates) => _sectors.ContainsKey(coordinates); + internal bool TorpedoCollisionAt(Coordinates coordinates, out string message, out bool gameOver) { gameOver = false; @@ -74,7 +97,7 @@ namespace SuperStarTrek.Space { case Klingon klingon: message = Remove(klingon); - gameOver = _galaxy.KlingonCount == 0; + gameOver = Galaxy.KlingonCount == 0; return true; case Star _: @@ -85,8 +108,8 @@ namespace SuperStarTrek.Space _sectors.Remove(coordinates); _info.RemoveStarbase(); message = "*** Starbase destroyed ***" + - (_galaxy.StarbaseCount > 0 ? Strings.CourtMartial : Strings.RelievedOfCommand); - gameOver = _galaxy.StarbaseCount == 0; + (Galaxy.StarbaseCount > 0 ? Strings.CourtMartial : Strings.RelievedOfCommand); + gameOver = Galaxy.StarbaseCount == 0; return true; default: @@ -101,6 +124,19 @@ namespace SuperStarTrek.Space return "*** Klingon destroyed ***"; } + internal CommandResult KlingonsMoveAndFire() + { + foreach (var klingon in Klingons.ToList()) + { + var newSector = GetRandomEmptySector(); + _sectors.Remove(klingon.Sector); + _sectors[newSector] = klingon; + klingon.MoveTo(newSector); + } + + return KlingonsFireOnEnterprise(); + } + internal CommandResult KlingonsFireOnEnterprise() { if (EnterpriseIsNextToStarbase && Klingons.Any()) diff --git a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs index 8b4357db..70447250 100644 --- a/84 Super Star Trek/csharp/Space/QuadrantInfo.cs +++ b/84 Super Star Trek/csharp/Space/QuadrantInfo.cs @@ -41,11 +41,7 @@ namespace SuperStarTrek.Space internal void AddStarbase() => HasStarbase = true; - internal Quadrant BuildQuadrant(Enterprise enterprise, Random random, Galaxy galaxy, Input input, Output output) - { - _isKnown = true; - return new(this, enterprise, random, galaxy, input, output); - } + internal void MarkAsKnown() => _isKnown = true; internal string Scan() { diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs index c8b195f4..ff6239ed 100644 --- a/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/DirectionDistanceCalculator.cs @@ -21,7 +21,8 @@ namespace SuperStarTrek.Systems.ComputerFunctions internal override void Execute(Quadrant quadrant) { Output.WriteLine("Direction/distance calculator:") - .WriteLine($"You are at quadrant {_enterprise.Quadrant} sector {_enterprise.Sector}") + .Write($"You are at quadrant {_enterprise.QuadrantCoordinates}") + .WriteLine($" sector {_enterprise.SectorCoordinates}") .WriteLine("Please enter"); WriteDirectionAndDistance( diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs index b81a353d..0d2c5b50 100644 --- a/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/StarbaseDataCalculator.cs @@ -24,7 +24,7 @@ namespace SuperStarTrek.Systems.ComputerFunctions Output.WriteLine("From Enterprise to Starbase:"); - WriteDirectionAndDistance(_enterprise.Sector, quadrant.Starbase.Sector); + WriteDirectionAndDistance(_enterprise.SectorCoordinates, quadrant.Starbase.Sector); } } } \ No newline at end of file diff --git a/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs b/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs index 6afa7b8c..09c71859 100644 --- a/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs +++ b/84 Super Star Trek/csharp/Systems/ComputerFunctions/TorpedoDataCalculator.cs @@ -26,7 +26,7 @@ namespace SuperStarTrek.Systems.ComputerFunctions foreach (var klingon in quadrant.Klingons) { - WriteDirectionAndDistance(_enterprise.Sector, klingon.Sector); + WriteDirectionAndDistance(_enterprise.SectorCoordinates, klingon.Sector); } } } diff --git a/84 Super Star Trek/csharp/Systems/PhaserControl.cs b/84 Super Star Trek/csharp/Systems/PhaserControl.cs index 48da4ace..5aa7cf8b 100644 --- a/84 Super Star Trek/csharp/Systems/PhaserControl.cs +++ b/84 Super Star Trek/csharp/Systems/PhaserControl.cs @@ -75,7 +75,7 @@ namespace SuperStarTrek.Systems private void ResolveHitOn(Klingon klingon, float perEnemyStrength, Quadrant quadrant) { - var distance = _enterprise.Sector.GetDistanceTo(klingon.Sector); + var distance = _enterprise.SectorCoordinates.GetDistanceTo(klingon.Sector); var hitStrength = (int)(perEnemyStrength / distance * (2 + _random.GetFloat())); if (klingon.TakeHit(hitStrength)) diff --git a/84 Super Star Trek/csharp/Systems/PhotonTubes.cs b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs index 034199c9..024cf7ea 100644 --- a/84 Super Star Trek/csharp/Systems/PhotonTubes.cs +++ b/84 Super Star Trek/csharp/Systems/PhotonTubes.cs @@ -34,15 +34,14 @@ namespace SuperStarTrek.Systems protected override CommandResult ExecuteCommandCore(Quadrant quadrant) { - if (!_input.TryGetNumber("Photon torpedo course", 1, 9, out var direction)) + if (!_input.TryGetCourse("Photon torpedo course", "Ensign Chekov", out var course)) { - _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)) + foreach (var sector in course.GetSectorsFrom(_enterprise.SectorCoordinates)) { _output.WriteLine($" {sector}"); diff --git a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs index e01c829e..e25cf966 100644 --- a/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs +++ b/84 Super Star Trek/csharp/Systems/ShortRangeSensors.cs @@ -51,8 +51,8 @@ namespace SuperStarTrek.Systems { yield return $"Stardate {_game.Stardate}"; yield return $"Condition {_enterprise.Condition}"; - yield return $"Quadrant {_enterprise.Quadrant}"; - yield return $"Sector {_enterprise.Sector}"; + yield return $"Quadrant {_enterprise.QuadrantCoordinates}"; + yield return $"Sector {_enterprise.SectorCoordinates}"; yield return $"Photon torpedoes {_enterprise.TorpedoCount}"; yield return $"Total energy {Math.Ceiling(_enterprise.TotalEnergy)}"; yield return $"Shields {(int)_enterprise.ShieldControl.ShieldEnergy}"; diff --git a/84 Super Star Trek/csharp/Systems/Subsystem.cs b/84 Super Star Trek/csharp/Systems/Subsystem.cs index ab7bef4c..9e5f3570 100644 --- a/84 Super Star Trek/csharp/Systems/Subsystem.cs +++ b/84 Super Star Trek/csharp/Systems/Subsystem.cs @@ -41,13 +41,26 @@ namespace SuperStarTrek.Systems public virtual void Repair() { - if (IsDamaged) { Condition = 0; } + if (IsDamaged) + { + Condition = 0; + } } - internal void TakeDamage(float damage) + public virtual bool Repair(float repairWorkDone) { - Condition -= damage; - _output.WriteLine($"Damage Control reports, '{Name} damaged by the hit.'"); + if (IsDamaged) + { + Condition += repairWorkDone; + if (Condition > -0.1f && Condition < 0) + { + Condition = -0.1f; + } + } + + return !IsDamaged; } + + internal void TakeDamage(float damage) => Condition -= damage; } } diff --git a/84 Super Star Trek/csharp/Systems/WarpEngines.cs b/84 Super Star Trek/csharp/Systems/WarpEngines.cs new file mode 100644 index 00000000..8e24b750 --- /dev/null +++ b/84 Super Star Trek/csharp/Systems/WarpEngines.cs @@ -0,0 +1,75 @@ +using System; +using SuperStarTrek.Commands; +using SuperStarTrek.Objects; +using SuperStarTrek.Space; + +namespace SuperStarTrek.Systems +{ + internal class WarpEngines : Subsystem + { + private readonly Enterprise _enterprise; + private readonly Output _output; + private readonly Input _input; + + public WarpEngines(Enterprise enterprise, Output output, Input input) + : base("Warp Engines", Command.NAV, output) + { + _enterprise = enterprise; + _output = output; + _input = input; + } + + protected override CommandResult ExecuteCommandCore(Quadrant quadrant) + { + if (_input.TryGetCourse("Course", " Lt. Sulu", out var course) && + TryGetWarpFactor(out var warpFactor) && + TryGetDistanceToMove(warpFactor, out var distanceToMove)) + { + var result = quadrant.KlingonsMoveAndFire(); + if (result.IsGameOver) { return result; } + + _enterprise.RepairSystems(warpFactor); + _enterprise.VaryConditionOfRandomSystem(); + var timeElapsed = _enterprise.Move(course, warpFactor, distanceToMove); + + return CommandResult.Elapsed(timeElapsed); + } + + return CommandResult.Ok; + } + + private bool TryGetWarpFactor(out float warpFactor) + { + var maximumWarp = IsDamaged ? 0.2f : 8; + if (_input.TryGetNumber("Warp Factor", 0, maximumWarp, out warpFactor)) + { + return warpFactor > 0; + } + + _output.WriteLine( + IsDamaged && warpFactor > maximumWarp + ? "Warp engines are damaged. Maximum speed = warp 0.2" + : $" Chief Engineer Scott reports, 'The engines won't take warp {warpFactor} !'"); + + return false; + } + + private bool TryGetDistanceToMove(float warpFactor, out int distanceToTravel) + { + distanceToTravel = (int)Math.Round(warpFactor * 8, MidpointRounding.AwayFromZero); + if (distanceToTravel <= _enterprise.Energy) { return true; } + + _output.WriteLine("Engineering reports, 'Insufficient energy available") + .WriteLine($" for maneuvering at warp {warpFactor} !'"); + + if (distanceToTravel <= _enterprise.TotalEnergy && !_enterprise.ShieldControl.IsDamaged) + { + _output.Write($"Deflector control room acknowledges {_enterprise.ShieldControl.ShieldEnergy} ") + .WriteLine("units of energy") + .WriteLine(" presently deployed to shields."); + } + + return false; + } + } +}