Add Phaser Control

This commit is contained in:
Andrew Cooper
2021-03-11 12:13:02 +11:00
parent b422db3f4a
commit 4b352db8ef
6 changed files with 125 additions and 9 deletions

View File

@@ -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))

View File

@@ -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; }

View File

@@ -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;
}
}
}

View File

@@ -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;
}
}
}

View File

@@ -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())

View File

@@ -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}");
}
}
}
}