feat(tyrant): add reign control panel
This commit is contained in:
@@ -0,0 +1,72 @@
|
||||
package games.dmg.spigottyrant;
|
||||
|
||||
import static org.mockito.ArgumentMatchers.any;
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.time.Clock;
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.time.ZoneOffset;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class DefaultTyrantControlPanelTest {
|
||||
@Test
|
||||
void nonTyrantCannotRenderControlPanel() {
|
||||
UUID tyrantId = UUID.fromString("11111111-1111-1111-1111-111111111111");
|
||||
UUID otherId = UUID.fromString("22222222-2222-2222-2222-222222222222");
|
||||
GameState game = new GameState(
|
||||
GameLifecycle.RUNNING, Optional.of(tyrantId), Optional.empty(),
|
||||
Optional.empty(), Optional.empty(), Optional.empty(), Duration.ZERO,
|
||||
0, 0, Set.of()
|
||||
);
|
||||
TyrantStateManager manager = mock(TyrantStateManager.class);
|
||||
when(manager.game()).thenReturn(game);
|
||||
Player other = mock(Player.class);
|
||||
when(other.getUniqueId()).thenReturn(otherId);
|
||||
TyrantControlPanelRenderer renderer = mock(TyrantControlPanelRenderer.class);
|
||||
DefaultTyrantControlPanel panel = new DefaultTyrantControlPanel(
|
||||
manager, renderer,
|
||||
Clock.fixed(Instant.parse("2026-08-21T12:00:00Z"), ZoneOffset.UTC)
|
||||
);
|
||||
|
||||
panel.open(other);
|
||||
|
||||
verify(renderer, never()).openOverview(any(), any());
|
||||
verify(other).sendMessage(org.mockito.ArgumentMatchers.contains("active Tyrant"));
|
||||
}
|
||||
|
||||
@Test
|
||||
void openingAsActiveTyrantRendersAuthoritativeOverview() {
|
||||
UUID tyrantId = UUID.fromString("11111111-1111-1111-1111-111111111111");
|
||||
GameState game = new GameState(
|
||||
GameLifecycle.RUNNING, Optional.of(tyrantId), Optional.empty(),
|
||||
Optional.empty(), Optional.empty(), Optional.empty(), Duration.ZERO,
|
||||
2, 1, Set.of(TyrantUnlock.STRENGTH)
|
||||
);
|
||||
PlayerState tyrantState = PlayerState.newPlayer(tyrantId, "Tyrant");
|
||||
TyrantStateManager manager = mock(TyrantStateManager.class);
|
||||
when(manager.game()).thenReturn(game);
|
||||
when(manager.player(tyrantId, "Tyrant")).thenReturn(tyrantState);
|
||||
when(manager.players()).thenReturn(Map.of(tyrantId, tyrantState));
|
||||
Player tyrant = mock(Player.class);
|
||||
when(tyrant.getUniqueId()).thenReturn(tyrantId);
|
||||
when(tyrant.getName()).thenReturn("Tyrant");
|
||||
TyrantControlPanelRenderer renderer = mock(TyrantControlPanelRenderer.class);
|
||||
DefaultTyrantControlPanel panel = new DefaultTyrantControlPanel(
|
||||
manager, renderer,
|
||||
Clock.fixed(Instant.parse("2026-08-21T12:00:00Z"), ZoneOffset.UTC)
|
||||
);
|
||||
|
||||
panel.open(tyrant);
|
||||
|
||||
verify(renderer).openOverview(org.mockito.ArgumentMatchers.eq(tyrant), any());
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,29 @@ import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
final class TyrantCommandTest {
|
||||
@Test
|
||||
void activeTyrantCanOpenControlPanelWithNoArgumentsOrMenuSubcommand() {
|
||||
UUID tyrantId = UUID.fromString("11111111-1111-1111-1111-111111111111");
|
||||
GameState game = new GameState(
|
||||
GameLifecycle.RUNNING, Optional.of(tyrantId), Optional.empty(),
|
||||
Optional.empty(), Optional.empty(), Optional.empty(), Duration.ZERO,
|
||||
0, 1, Set.of()
|
||||
);
|
||||
TyrantStateManager manager = mock(TyrantStateManager.class);
|
||||
when(manager.game()).thenReturn(game);
|
||||
Player tyrant = mock(Player.class);
|
||||
when(tyrant.getUniqueId()).thenReturn(tyrantId);
|
||||
TyrantControlPanel controlPanel = mock(TyrantControlPanel.class);
|
||||
TyrantCommand command = new TyrantCommand(
|
||||
manager, new TyrantProgressionService(), controlPanel
|
||||
);
|
||||
|
||||
command.onCommand(tyrant, mock(Command.class), "tyrant", new String[0]);
|
||||
command.onCommand(tyrant, mock(Command.class), "tyrant", new String[] {"menu"});
|
||||
|
||||
verify(controlPanel, org.mockito.Mockito.times(2)).open(tyrant);
|
||||
}
|
||||
|
||||
@Test
|
||||
void choicesClearlyIdentifyPurchasedAvailableAndUnavailableUnlocks() {
|
||||
UUID tyrantId = UUID.fromString("11111111-1111-1111-1111-111111111111");
|
||||
|
||||
@@ -0,0 +1,105 @@
|
||||
package games.dmg.spigottyrant;
|
||||
|
||||
import static org.mockito.Mockito.mock;
|
||||
import static org.mockito.Mockito.never;
|
||||
import static org.mockito.Mockito.verify;
|
||||
import static org.mockito.Mockito.when;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.bukkit.entity.Player;
|
||||
import org.bukkit.event.player.PlayerJoinEvent;
|
||||
import org.junit.jupiter.api.Test;
|
||||
import org.mockito.ArgumentCaptor;
|
||||
|
||||
final class TyrantControlPanelJoinListenerTest {
|
||||
@Test
|
||||
void delayedTaskDoesNotOpenAfterEventPauses() {
|
||||
UUID tyrantId = UUID.fromString("11111111-1111-1111-1111-111111111111");
|
||||
GameState paused = new GameState(
|
||||
GameLifecycle.PAUSED, Optional.of(tyrantId), Optional.empty(),
|
||||
Optional.empty(), Optional.empty(), Optional.of(java.time.Instant.EPOCH),
|
||||
Duration.ZERO, 0, 1, Set.of()
|
||||
);
|
||||
TyrantStateManager manager = mock(TyrantStateManager.class);
|
||||
when(manager.game()).thenReturn(paused);
|
||||
Player tyrant = mock(Player.class);
|
||||
when(tyrant.getUniqueId()).thenReturn(tyrantId);
|
||||
when(tyrant.isOnline()).thenReturn(true);
|
||||
PlayerJoinEvent event = mock(PlayerJoinEvent.class);
|
||||
when(event.getPlayer()).thenReturn(tyrant);
|
||||
DelayedTaskScheduler scheduler = mock(DelayedTaskScheduler.class);
|
||||
TyrantControlPanel panel = mock(TyrantControlPanel.class);
|
||||
TyrantControlPanelJoinListener listener = new TyrantControlPanelJoinListener(
|
||||
manager, panel, scheduler
|
||||
);
|
||||
|
||||
listener.onJoin(event);
|
||||
ArgumentCaptor<Runnable> task = ArgumentCaptor.forClass(Runnable.class);
|
||||
verify(scheduler).schedule(task.capture(), org.mockito.ArgumentMatchers.eq(100L));
|
||||
task.getValue().run();
|
||||
|
||||
verify(panel, never()).open(tyrant);
|
||||
}
|
||||
|
||||
@Test
|
||||
void delayedTaskDoesNotReopenPanelOpenedManually() {
|
||||
UUID tyrantId = UUID.fromString("11111111-1111-1111-1111-111111111111");
|
||||
GameState game = new GameState(
|
||||
GameLifecycle.RUNNING, Optional.of(tyrantId), Optional.empty(),
|
||||
Optional.empty(), Optional.empty(), Optional.empty(), Duration.ZERO,
|
||||
0, 1, Set.of()
|
||||
);
|
||||
TyrantStateManager manager = mock(TyrantStateManager.class);
|
||||
when(manager.game()).thenReturn(game);
|
||||
Player tyrant = mock(Player.class);
|
||||
when(tyrant.getUniqueId()).thenReturn(tyrantId);
|
||||
when(tyrant.isOnline()).thenReturn(true);
|
||||
PlayerJoinEvent event = mock(PlayerJoinEvent.class);
|
||||
when(event.getPlayer()).thenReturn(tyrant);
|
||||
DelayedTaskScheduler scheduler = mock(DelayedTaskScheduler.class);
|
||||
TyrantControlPanel panel = mock(TyrantControlPanel.class);
|
||||
when(panel.openedThisSession(tyrantId)).thenReturn(true);
|
||||
TyrantControlPanelJoinListener listener = new TyrantControlPanelJoinListener(
|
||||
manager, panel, scheduler
|
||||
);
|
||||
|
||||
listener.onJoin(event);
|
||||
ArgumentCaptor<Runnable> task = ArgumentCaptor.forClass(Runnable.class);
|
||||
verify(scheduler).schedule(task.capture(), org.mockito.ArgumentMatchers.eq(100L));
|
||||
task.getValue().run();
|
||||
|
||||
verify(panel, never()).open(tyrant);
|
||||
}
|
||||
|
||||
@Test
|
||||
void opensPanelOneHundredTicksAfterActiveTyrantJoins() {
|
||||
UUID tyrantId = UUID.fromString("11111111-1111-1111-1111-111111111111");
|
||||
GameState game = new GameState(
|
||||
GameLifecycle.RUNNING, Optional.of(tyrantId), Optional.empty(),
|
||||
Optional.empty(), Optional.empty(), Optional.empty(), Duration.ZERO,
|
||||
0, 1, Set.of()
|
||||
);
|
||||
TyrantStateManager manager = mock(TyrantStateManager.class);
|
||||
when(manager.game()).thenReturn(game);
|
||||
Player tyrant = mock(Player.class);
|
||||
when(tyrant.getUniqueId()).thenReturn(tyrantId);
|
||||
when(tyrant.isOnline()).thenReturn(true);
|
||||
PlayerJoinEvent event = mock(PlayerJoinEvent.class);
|
||||
when(event.getPlayer()).thenReturn(tyrant);
|
||||
DelayedTaskScheduler scheduler = mock(DelayedTaskScheduler.class);
|
||||
TyrantControlPanel panel = mock(TyrantControlPanel.class);
|
||||
TyrantControlPanelJoinListener listener = new TyrantControlPanelJoinListener(
|
||||
manager, panel, scheduler
|
||||
);
|
||||
|
||||
listener.onJoin(event);
|
||||
|
||||
ArgumentCaptor<Runnable> task = ArgumentCaptor.forClass(Runnable.class);
|
||||
verify(scheduler).schedule(task.capture(), org.mockito.ArgumentMatchers.eq(100L));
|
||||
task.getValue().run();
|
||||
verify(panel).open(tyrant);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,49 @@
|
||||
package games.dmg.spigottyrant;
|
||||
|
||||
import static org.junit.jupiter.api.Assertions.assertEquals;
|
||||
|
||||
import java.time.Duration;
|
||||
import java.time.Instant;
|
||||
import java.util.Map;
|
||||
import java.util.Optional;
|
||||
import java.util.Set;
|
||||
import java.util.UUID;
|
||||
import org.junit.jupiter.api.Test;
|
||||
|
||||
final class TyrantControlPanelModelTest {
|
||||
@Test
|
||||
void overviewShowsProgressPurchasesAssignmentsAndIntelligenceCooldown() {
|
||||
UUID tyrantId = UUID.fromString("11111111-1111-1111-1111-111111111111");
|
||||
UUID assassinId = UUID.fromString("22222222-2222-2222-2222-222222222222");
|
||||
Instant now = Instant.parse("2026-08-21T12:00:00Z");
|
||||
GameState game = new GameState(
|
||||
GameLifecycle.RUNNING, Optional.of(tyrantId), Optional.empty(),
|
||||
Optional.empty(), Optional.empty(), Optional.empty(), Duration.ZERO,
|
||||
3, 2, Set.of(TyrantUnlock.ASSASSIN, TyrantUnlock.ROSTER_INTELLIGENCE)
|
||||
);
|
||||
PlayerState tyrant = new PlayerState(
|
||||
tyrantId, "Tyrant", Optional.of(now), Optional.empty(), TyrantClass.NONE,
|
||||
Optional.empty(), Map.of(Ability.ROSTER_INTELLIGENCE, now.plusSeconds(90)),
|
||||
Set.of(), java.util.List.of()
|
||||
);
|
||||
PlayerState assassin = new PlayerState(
|
||||
assassinId, "Blade", Optional.of(now), Optional.empty(), TyrantClass.ASSASSIN,
|
||||
Optional.empty(), Map.of(), Set.of(), java.util.List.of()
|
||||
);
|
||||
|
||||
TyrantControlPanelModel model = TyrantControlPanelModel.create(
|
||||
game, tyrant, Map.of(tyrantId, tyrant, assassinId, assassin), now
|
||||
);
|
||||
|
||||
assertEquals(3, model.level());
|
||||
assertEquals(2, model.unspentChoices());
|
||||
assertEquals(UnlockAvailability.PURCHASED,
|
||||
model.unlocks().get(TyrantUnlock.ASSASSIN));
|
||||
assertEquals(
|
||||
Set.of(TyrantUnlock.ASSASSIN, TyrantUnlock.ROSTER_INTELLIGENCE),
|
||||
model.purchasedUnlocks()
|
||||
);
|
||||
assertEquals("Blade", model.classHolders().get(TyrantClass.ASSASSIN));
|
||||
assertEquals(Duration.ofSeconds(90), model.intelligenceCooldown());
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user