Files
basic-computer-games/84_Super_Star_Trek/csharp/Systems/PhaserControl.cs
2022-03-22 17:55:44 +11:00

97 lines
2.8 KiB
C#

using System.Linq;
using Games.Common.IO;
using Games.Common.Randomness;
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 IReadWrite _io;
private readonly IRandom _random;
internal PhaserControl(Enterprise enterprise, IReadWrite io, IRandom random)
: base("Phaser Control", Command.PHA, io)
{
_enterprise = enterprise;
_io = io;
_random = random;
}
protected override bool CanExecuteCommand() => IsOperational("Phasers inoperative");
protected override CommandResult ExecuteCommandCore(Quadrant quadrant)
{
if (!quadrant.HasKlingons)
{
_io.WriteLine(Strings.NoEnemyShips);
return CommandResult.Ok;
}
if (_enterprise.Computer.IsDamaged)
{
_io.WriteLine("Computer failure hampers accuracy");
}
_io.Write($"Phasers locked on target; ");
var phaserStrength = GetPhaserStrength();
if (phaserStrength < 0) { return CommandResult.Ok; }
_enterprise.UseEnergy(phaserStrength);
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)
{
_io.WriteLine($"Energy available = {_enterprise.Energy} units");
var phaserStrength = _io.ReadNumber("Number of units to fire");
if (phaserStrength <= _enterprise.Energy) { return phaserStrength; }
}
}
private float GetPerTargetPhaserStrength(float phaserStrength, int targetCount)
{
if (_enterprise.Computer.IsDamaged)
{
phaserStrength *= _random.NextFloat();
}
return phaserStrength / targetCount;
}
private void ResolveHitOn(Klingon klingon, float perEnemyStrength, Quadrant quadrant)
{
var distance = _enterprise.SectorCoordinates.GetDistanceTo(klingon.Sector);
var hitStrength = (int)(perEnemyStrength / distance * (2 + _random.NextFloat()));
if (klingon.TakeHit(hitStrength))
{
_io.WriteLine($"{hitStrength} unit hit on Klingon at sector {klingon.Sector}");
_io.WriteLine(
klingon.Energy <= 0
? quadrant.Remove(klingon)
: $" (sensors show {klingon.Energy} units remaining)");
}
else
{
_io.WriteLine($"Sensors show no damage to enemy at {klingon.Sector}");
}
}
}