feat: support curated abilities and objective victory
This commit is contained in:
committed by
Keith Solomon
parent
088e85c9b4
commit
6befe7b3e2
@@ -4,6 +4,7 @@ declare(strict_types=1);
|
||||
|
||||
namespace BattleForge\Tests\Unit\Domain;
|
||||
|
||||
use BattleForge\Domain\Archetype;
|
||||
use BattleForge\Domain\Battlefield;
|
||||
use BattleForge\Domain\CombatEngine;
|
||||
use BattleForge\Domain\CombatException;
|
||||
@@ -583,7 +584,7 @@ final class CombatEngineTest extends TestCase
|
||||
);
|
||||
|
||||
$this->expectException(CombatException::class);
|
||||
$this->expectExceptionMessage('Matches require alpha and bravo teams.');
|
||||
$this->expectExceptionMessage('Matches require exactly two teams.');
|
||||
|
||||
(new CombatEngine())->endTurn($match);
|
||||
}
|
||||
@@ -594,7 +595,6 @@ final class CombatEngineTest extends TestCase
|
||||
public static function invalidEndTurnTeamProvider(): iterable
|
||||
{
|
||||
yield 'only alpha' => [['alpha']];
|
||||
yield 'alpha and charlie' => [['alpha', 'charlie']];
|
||||
yield 'alpha, bravo, and charlie' => [['alpha', 'bravo', 'charlie']];
|
||||
}
|
||||
|
||||
@@ -746,6 +746,7 @@ final class CombatEngineTest extends TestCase
|
||||
int $attack = 4,
|
||||
int $defense = 2,
|
||||
bool $hasAttacked = false,
|
||||
int $attackBonus = 0,
|
||||
): UnitState {
|
||||
return new UnitState(
|
||||
$id,
|
||||
@@ -758,6 +759,218 @@ final class CombatEngineTest extends TestCase
|
||||
$speed,
|
||||
$actionsRemaining,
|
||||
$hasAttacked,
|
||||
attackBonus: $attackBonus,
|
||||
);
|
||||
}
|
||||
|
||||
public function testHealAbilityRestoresAlliedHealthAndConsumesOneAction(): void
|
||||
{
|
||||
$caster = new UnitState(
|
||||
id: 'support-1',
|
||||
teamId: 'alpha',
|
||||
position: new Position(0, 0),
|
||||
maxHealth: 8,
|
||||
health: 8,
|
||||
attack: 2,
|
||||
defense: 2,
|
||||
speed: 3,
|
||||
actionsRemaining: 2,
|
||||
hasAttacked: false,
|
||||
archetype: Archetype::Support,
|
||||
abilities: ['heal'],
|
||||
attackBonus: 0,
|
||||
hasUsedAbility: false,
|
||||
);
|
||||
$wounded = new UnitState(
|
||||
id: 'alpha-1',
|
||||
teamId: 'alpha',
|
||||
position: new Position(0, 1),
|
||||
maxHealth: 10,
|
||||
health: 3,
|
||||
attack: 4,
|
||||
defense: 2,
|
||||
speed: 4,
|
||||
actionsRemaining: 2,
|
||||
hasAttacked: false,
|
||||
);
|
||||
$bravo = $this->unit('bravo-1', 'bravo', new Position(7, 7));
|
||||
$match = new MatchState(
|
||||
new Battlefield(8, 8),
|
||||
[$caster, $wounded, $bravo],
|
||||
'alpha',
|
||||
);
|
||||
|
||||
$next = (new CombatEngine())->useAbility($match, 'support-1', 'heal', new Position(0, 1));
|
||||
|
||||
self::assertSame(8, $next->unit('alpha-1')->health);
|
||||
self::assertSame(1, $next->unit('support-1')->actionsRemaining);
|
||||
self::assertTrue($next->unit('support-1')->hasUsedAbility);
|
||||
self::assertSame(['support-1 used Heal on alpha-1 for 5'], $next->actionLog);
|
||||
}
|
||||
|
||||
public function testAreaDamageAbilityHitsEveryEnemyInsideTheRadius(): void
|
||||
{
|
||||
$caster = new UnitState(
|
||||
id: 'striker-1',
|
||||
teamId: 'alpha',
|
||||
position: new Position(0, 0),
|
||||
maxHealth: 8,
|
||||
health: 8,
|
||||
attack: 5,
|
||||
defense: 1,
|
||||
speed: 3,
|
||||
actionsRemaining: 2,
|
||||
hasAttacked: false,
|
||||
archetype: Archetype::Striker,
|
||||
abilities: ['area_damage'],
|
||||
attackBonus: 0,
|
||||
hasUsedAbility: false,
|
||||
);
|
||||
$alpha = $this->unit('alpha-2', 'alpha', new Position(2, 0));
|
||||
$bravoA = $this->unit('bravo-1', 'bravo', new Position(1, 1), defense: 1);
|
||||
$bravoB = $this->unit('bravo-2', 'bravo', new Position(2, 1), defense: 1);
|
||||
$bravoC = $this->unit('bravo-3', 'bravo', new Position(3, 1), defense: 1);
|
||||
$bravoD = $this->unit('bravo-4', 'bravo', new Position(5, 5));
|
||||
$match = new MatchState(
|
||||
new Battlefield(8, 8),
|
||||
[$caster, $alpha, $bravoA, $bravoB, $bravoC, $bravoD],
|
||||
'alpha',
|
||||
);
|
||||
|
||||
$next = (new CombatEngine())->useAbility($match, 'striker-1', 'area_damage', new Position(2, 1));
|
||||
|
||||
self::assertSame(8, $next->unit('bravo-1')->health);
|
||||
self::assertSame(8, $next->unit('bravo-2')->health);
|
||||
self::assertSame(8, $next->unit('bravo-3')->health);
|
||||
self::assertSame(10, $next->unit('bravo-4')->health);
|
||||
self::assertSame(10, $next->unit('alpha-2')->health);
|
||||
self::assertSame(1, $next->unit('striker-1')->actionsRemaining);
|
||||
}
|
||||
|
||||
public function testBuffAbilityReplacesTheAttackBonusOnAnAlly(): void
|
||||
{
|
||||
$caster = new UnitState(
|
||||
id: 'support-1',
|
||||
teamId: 'alpha',
|
||||
position: new Position(0, 0),
|
||||
maxHealth: 8,
|
||||
health: 8,
|
||||
attack: 2,
|
||||
defense: 2,
|
||||
speed: 3,
|
||||
actionsRemaining: 2,
|
||||
hasAttacked: false,
|
||||
archetype: Archetype::Support,
|
||||
abilities: ['buff'],
|
||||
attackBonus: 0,
|
||||
hasUsedAbility: false,
|
||||
);
|
||||
$alpha = $this->unit('alpha-2', 'alpha', new Position(0, 1), attackBonus: 1);
|
||||
$bravo = $this->unit('bravo-1', 'bravo', new Position(7, 7));
|
||||
$match = new MatchState(
|
||||
new Battlefield(8, 8),
|
||||
[$caster, $alpha, $bravo],
|
||||
'alpha',
|
||||
);
|
||||
|
||||
$next = (new CombatEngine())->useAbility($match, 'support-1', 'buff', new Position(0, 1));
|
||||
|
||||
self::assertSame(2, $next->unit('alpha-2')->attackBonus);
|
||||
}
|
||||
|
||||
public function testUseAbilityRejectsAUnitThatHasAlreadyUsedOne(): void
|
||||
{
|
||||
$caster = new UnitState(
|
||||
id: 'support-1',
|
||||
teamId: 'alpha',
|
||||
position: new Position(0, 0),
|
||||
maxHealth: 8,
|
||||
health: 8,
|
||||
attack: 2,
|
||||
defense: 2,
|
||||
speed: 3,
|
||||
actionsRemaining: 2,
|
||||
hasAttacked: false,
|
||||
archetype: Archetype::Support,
|
||||
abilities: ['heal'],
|
||||
attackBonus: 0,
|
||||
hasUsedAbility: true,
|
||||
);
|
||||
$alpha = $this->unit('alpha-2', 'alpha', new Position(0, 1));
|
||||
$bravo = $this->unit('bravo-1', 'bravo', new Position(7, 7));
|
||||
$match = new MatchState(
|
||||
new Battlefield(8, 8),
|
||||
[$caster, $alpha, $bravo],
|
||||
'alpha',
|
||||
);
|
||||
|
||||
$this->expectException(CombatException::class);
|
||||
$this->expectExceptionMessage('Unit has already used an ability this turn.');
|
||||
|
||||
(new CombatEngine())->useAbility($match, 'support-1', 'heal', new Position(0, 1));
|
||||
}
|
||||
|
||||
public function testUseAbilityRejectsTargetsOutsideRange(): void
|
||||
{
|
||||
$caster = new UnitState(
|
||||
id: 'support-1',
|
||||
teamId: 'alpha',
|
||||
position: new Position(0, 0),
|
||||
maxHealth: 8,
|
||||
health: 8,
|
||||
attack: 2,
|
||||
defense: 2,
|
||||
speed: 3,
|
||||
actionsRemaining: 2,
|
||||
hasAttacked: false,
|
||||
archetype: Archetype::Support,
|
||||
abilities: ['heal'],
|
||||
attackBonus: 0,
|
||||
hasUsedAbility: false,
|
||||
);
|
||||
$alpha = $this->unit('alpha-2', 'alpha', new Position(5, 5));
|
||||
$bravo = $this->unit('bravo-1', 'bravo', new Position(7, 7));
|
||||
$match = new MatchState(
|
||||
new Battlefield(8, 8),
|
||||
[$caster, $alpha, $bravo],
|
||||
'alpha',
|
||||
);
|
||||
|
||||
$this->expectException(CombatException::class);
|
||||
$this->expectExceptionMessage('Ability target is out of range.');
|
||||
|
||||
(new CombatEngine())->useAbility($match, 'support-1', 'heal', new Position(5, 5));
|
||||
}
|
||||
|
||||
public function testUseAbilityRejectsAnAbilityTheArchetypeForbids(): void
|
||||
{
|
||||
$caster = new UnitState(
|
||||
id: 'scout-1',
|
||||
teamId: 'alpha',
|
||||
position: new Position(0, 0),
|
||||
maxHealth: 6,
|
||||
health: 6,
|
||||
attack: 3,
|
||||
defense: 1,
|
||||
speed: 5,
|
||||
actionsRemaining: 2,
|
||||
hasAttacked: false,
|
||||
archetype: Archetype::Scout,
|
||||
abilities: [],
|
||||
attackBonus: 0,
|
||||
hasUsedAbility: false,
|
||||
);
|
||||
$alpha = $this->unit('alpha-2', 'alpha', new Position(0, 1));
|
||||
$bravo = $this->unit('bravo-1', 'bravo', new Position(7, 7));
|
||||
$match = new MatchState(
|
||||
new Battlefield(8, 8),
|
||||
[$caster, $alpha, $bravo],
|
||||
'alpha',
|
||||
);
|
||||
|
||||
$this->expectException(CombatException::class);
|
||||
$this->expectExceptionMessage('Unit does not know that ability.');
|
||||
|
||||
(new CombatEngine())->useAbility($match, 'scout-1', 'heal', new Position(0, 1));
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user