fix: enforce executable movement state
This commit is contained in:
@@ -4,13 +4,19 @@ declare(strict_types=1);
|
||||
|
||||
namespace BattleForge\Domain;
|
||||
|
||||
use InvalidArgumentException;
|
||||
|
||||
final class CombatEngine
|
||||
{
|
||||
public function move(MatchState $match, string $unitId, Position $destination): MatchState
|
||||
{
|
||||
$this->assertMatchActive($match);
|
||||
|
||||
$unit = $match->unit($unitId);
|
||||
try {
|
||||
$unit = $match->unit($unitId);
|
||||
} catch (InvalidArgumentException $exception) {
|
||||
throw new CombatException("Unknown unit: {$unitId}.", previous: $exception);
|
||||
}
|
||||
$this->assertCanAct($match, $unit);
|
||||
|
||||
$occupied = [];
|
||||
|
||||
@@ -30,6 +30,7 @@ final readonly class MatchState
|
||||
|
||||
$unitIds = [];
|
||||
$teamIds = [];
|
||||
$occupiedPositions = [];
|
||||
|
||||
foreach ($units as $unit) {
|
||||
if (!self::isUnitState($unit)) {
|
||||
@@ -40,6 +41,24 @@ final readonly class MatchState
|
||||
throw new InvalidArgumentException("Duplicate unit id: {$unit->id}.");
|
||||
}
|
||||
|
||||
if (!$battlefield->contains($unit->position)) {
|
||||
throw new InvalidArgumentException("Unit {$unit->id} is outside the battlefield.");
|
||||
}
|
||||
|
||||
if (!$unit->isDefeated() && $battlefield->terrainAt($unit->position)->movementCost() === null) {
|
||||
throw new InvalidArgumentException("Living unit {$unit->id} must stand on passable terrain.");
|
||||
}
|
||||
|
||||
$positionKey = $unit->position->key();
|
||||
|
||||
if (!$unit->isDefeated() && isset($occupiedPositions[$positionKey])) {
|
||||
throw new InvalidArgumentException("Living units cannot share position {$positionKey}.");
|
||||
}
|
||||
|
||||
if (!$unit->isDefeated()) {
|
||||
$occupiedPositions[$positionKey] = true;
|
||||
}
|
||||
|
||||
$unitIds[$unit->id] = true;
|
||||
$teamIds[$unit->teamId] = true;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user